关于oop:Python纯虚函数是否可行和/或值得?

Are Python pure virtual functions possible and/or worth it?

我可能来自不同的思维方式,主要是C++程序员。这个问题与Python中的OOP以及更具体的纯虚拟方法有关。所以,根据这个问题改编的代码,我将看到这个基本示例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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()

所以您可以看到它为不同的派生类调用speak函数。现在我的问题是鸭子打字很好,我想我已经掌握了。然而,在Python中追求更严格的OOP是错误的吗?所以我研究了抽象的基类和具体的抽象方法。对我来说,这一切似乎都是允许我用super调用基类方法。是否有任何方法/理由(在python中)使speak()变得纯粹,从而实现一个没有语言的派生动物会抛出一个错误?

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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()


抽象基类已经满足了您的需要。abstractmethod与允许您使用super调用方法无关;您无论如何都可以这样做。相反,必须重写用abstractmethod修饰的任何方法,以便子类可实例化:

Python3:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
>>> 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>

号Python2:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
>>> 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>


Problem is that this error is found at runtime!

嗯,是Python……大多数错误将在运行时出现。

据我所知,最常见的模式是在python中,基本上就是您所描述的:只要让基类的speak方法抛出一个异常:

1
2
3
class Animal():
    def speak(self):
        raise NotImplementedError('You need to define a speak method!')