Python纯虚函数是否可行和/或值得?

ben*_*eno 14 python oop pure-virtual

我可能来自不同的心态,主要是C++程序员.这个问题与Python中的OOP有关,更具体地说是纯虚方法.所以我从这个问题中改编代码,我正在研究这个基本样本.

class Animal():
    def speak(self):
        print("...")

class Cat(Animal):
    def speak(self):
        print("meow")

class Dog(Animal):
    def speak(self):
        print("woof")

my_pets = [Dog(), Cat(), Dog()]

for _pet in my_pets:
     _pet.speak()
Run Code Online (Sandbox Code Playgroud)

所以你看到它为不同的派生类调用了speak函数.现在我的问题是鸭子打字都很好,我想我已经掌握了它.但是,在Python中追求更严格的OOP是不对的?所以我查看了抽象基类,特别是抽象方法.对我来说,这似乎是允许我用super调用基类方法.有没有任何方法/理由(在Python中)使speak()纯粹的实现一个派生的动物没有说话会抛出错误?

我对这种追求的论证是在编写你打算让人们进行子类化的模块和框架时,这会为他们自己记录他们需要实现这个功能的事实.一个非常糟糕的想法就是这样,让基类"纯"函数抛出异常.问题是在运行时发现了这个错误!

class VirtualException(BaseException):
    def __init__(self, _type, _func):
        BaseException(self)

class Animal():
    def speak(self):
        raise VirtualException()

class Cat(Animal):
    def speak(self):
        print("meow")

class Dog(Animal):
    def speak(self):
        print("woof")

class Wildebeest(Animal):
    def function2(self):
        print("What!")

my_pets = [Dog(), Cat(), Dog(), Wildebeest()]

for _pet in my_pets:
    _pet.speak()
Run Code Online (Sandbox Code Playgroud)

use*_*ica 20

抽象基类已经做了你想要的.abstractmethod与让你调用方法无关super; 你无论如何都可以这样做.相反,abstractmethod必须覆盖任何装饰的方法,以使子类可以实例化:

Python 3:

>>> class Foo(metaclass=abc.ABCMeta):
...     @abc.abstractmethod
...     def foo(self):
...         pass
...
>>> class Bar(Foo):
...     pass
...
>>> class Baz(Bar):
...     def foo(self):
...         return super(Baz, self).foo()
...
>>> Foo()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class Foo with abstract methods foo
>>> Bar()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class Bar with abstract methods foo
>>> Baz()
<__main__.Baz object at 0x00000210D702E2B0>
Run Code Online (Sandbox Code Playgroud)

Python 2:

>>> class Foo(object):
...     __metaclass__ = abc.ABCMeta
...     @abc.abstractmethod
...     def foo(self): pass
...
>>> class Bar(Foo): pass
...
>>> class Baz(Bar):
...     def foo(self): return super(Baz, self).foo()
...
>>> Foo()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class Foo with abstract methods foo
>>> Bar()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class Bar with abstract methods foo
>>> Baz()
<__main__.Baz object at 0x0000000001EC10B8>
Run Code Online (Sandbox Code Playgroud)


Mar*_*ius 8

问题是在运行时发现了这个错误!

好吧,它是Python ......大多数错误都会在运行时出现.

据我所知,处理Python的最常见模式基本上就是你所描述的:只需让基类的speak方法抛出异常:

class Animal():
    def speak(self):
        raise NotImplementedError('You need to define a speak method!')
Run Code Online (Sandbox Code Playgroud)

  • +1"大多数错误将在运行时显示"! (5认同)