什么时候应该从 ABC 继承?

When should one inherit from ABC?

我一直认为应该从 abc.ABC 继承,而不希望 class 被实例化。但我刚刚意识到,如果 class 有一个 @abstractmethod 那么也不能实例化它。

是否有任何其他原因要从 ABC 继承?

除非您使用 abc.ABCMeta 作为 class 的元 class(明确地或继承自 abc.ABC),否则使用 abstractmethod 不会真的什么都做不了。

>>> from abc import abstractmethod, ABC
>>> class Foo:
...   @abstractmethod
...   def bar(self):
...     pass
...
>>> f = Foo()
>>>

同样,除非您将至少一种方法标记为抽象方法,否则使用 ABCMeta 意义不大:

>>> class Bar(ABC):
...     pass
...
>>> b = Bar()
>>>

正是这两者的结合使 class 成为(名义上)不可实例化的:

>>> class Baz(ABC):
...   @abstractmethod
...   def m(self):
...     pass
...
>>> b = Baz()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class Baz with abstract methods m
>>>

(即便如此,请注意所有 @abstractmethod 所做的就是将装饰方法添加到元 class 机制在尝试实例化 class 时参考的集合中。这是微不足道的打败那台机器:

>>> Baz.__abstractmethods__
frozenset({'m'})
>>> Baz.__abstractmethods__ = set()
>>> b = Baz()
>>>

)


请注意 ABC 本身是一个普通的 class,它使用 ABCMeta 作为它的元 class,这使得它的任何后代也使用它。

# Docstring omitted; see
# https://github.com/python/cpython/blob/3.7/Lib/abc.py#L166
# for the original
class ABC(metaclass=ABCMeta):
    __slots__ = ()

chepner 说的,还有可读性。继承自 ABC 让您的读者清楚地知道您在做什么。

>>> from abc import ABC, abstractmethod
>>> 
>>> class Foo:
...     @abstractmethod
...     def f(self):
...         pass
... 
>>> class Bar(Foo):
...     pass
... 
>>> Bar().f()
>>> 
>>> class Baz(ABC):
...     @abstractmethod
...     def f(self):
...         pass
... 
>>> class Quux(Baz):
...     pass
... 
>>> Quux().f()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class Quux with abstract methods f