什么时候应该从 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
我一直认为应该从 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