为了多态性而在抽象类中使用未实现的方法的必要性?

时间:2016-05-19 22:22:40

标签: python oop polymorphism

我不认为拥有它很重要,因为真正的实现无论如何都将在每个子类中实现。请考虑以下代码:

class Cat:
    def __init__(self, breed):
        self.breed = breed
    def sound(self): # having this or not does'nt make any difference
        pass

class Angora(Cat):
    def sound(self):
        print("miau")

class Scotish(Cat):
    def sound(self):
        print('meowww')

a = Angora('angora')
b = Scotish('scotish')

cats = [a, b]

for catt in cats:
    catt.sound()

我现在必须遗漏一些东西,因为我很难理解这个词。

4 个答案:

答案 0 :(得分:2)

你需要这样的东西,所以如果你忘了在任何子类中实现该方法,你会看到异常。

class Cat:
    def __init__(self, breed):
        self.breed = breed

    def sound(self):
        raise NotImplementedError('Should be implemented in subclass')

此外,它使类接口更清晰。

答案 1 :(得分:1)

即使不需要使代码工作,也有助于使代码自我记录,以便将来更容易实现Cat。我还可以在Cat对象上使用内省/反射。 另请参阅在此处向python添加“正确”抽象基类的动机:https://www.python.org/dev/peps/pep-3119/

答案 2 :(得分:1)

放置一个将被覆盖的空方法,没有多少意义,但如果Cat是一个实际的抽象类,而sound是一个强制的方法要被覆盖,那么它有很大的好处,例如:

import abc

class Cat(abc.ABC):
    def __init__(self, breed):
        self.breed = breed
    @abc.abstractmethod
    def sound(self): # having this as an abstract method DOES make a difference
        pass

class Scotish(Cat):
    def sonud(self):
        print('meowww')

您是否注意到拼写错误,尝试初始化Scotish时会出现此错误:

>>> b = Scotish("scotish")
Traceback (most recent call last):
  File "<pyshell#12>", line 1, in <module>
    b = Scotish("scotish")
TypeError: Can't instantiate abstract class Scotish with abstract methods sound

所以,在你得到任何奇怪的模糊错误之前,你会立刻得到实际出错的地方!

与简单的raise NotImplementedError不同,抽象方法可以包含很好的抽象代码!就像函数可能做的一个例子一样,一个很好的例子是_collections_abc.Generator.throw

@abstractmethod
def throw(self, typ, val=None, tb=None):
    """Raise an exception in the coroutine.
    Return next yielded value or raise StopIteration.
    """
    if val is None:
        if tb is None:
            raise typ
        val = typ()
    if tb is not None:
        val = val.with_traceback(tb)
    raise val

这不是真正的代码,这不是生成器实际处理throw方法的方式,但它是如何至少处理参数的一个很好的抽象

答案 3 :(得分:0)

到目前为止尚未说过的事情:

这是实施open closed principle的声音解决方案的关键要素。

关键点是:通常,您使用抽象基类来实现某种行为......对于所有子类应该是相同的。另一方面,这种“常见”实现可能需要调用子类特定方法才能完成其工作。

一些伪代码示例:

abstract class Base:
   final foo():
      return "foo" + infoFromChild()

   abstract infoFromChild()

然后:

  • 你可以在任何继承Base
  • 的对象上调用“foo()”
  • 您可以将每个子类中的空抽象“infoFromChild”覆盖为相应的内容

但当然:这些东西在Java或C ++等“更静态”的语言中更具“意义”。在python中,你可能会以不同的方式做事。