为什么@abstractmethod 需要在class 中使用,其metaclass 是从ABCMeta 派生的?
Why does @abstractmethod need to be used in a class whose metaclass is derived from ABCMeta?
PEP 3119 指出:
The @abstractmethod
decorator should only be used inside a class body, and only for classes whose metaclass is (derived from) ABCMeta
. Dynamically adding abstract methods to a class, or attempting to modify the abstraction status of a method or class once it is created, are not supported.
但是,我找不到原因的解释。具体来说,我没有注意到在未明确继承自 ABCMeta
的 class 中仅使用 @abstractmethod
时的行为差异。在下面这个简单的例子中,如果我理解正确的话,正确的做法是:
import six
from abc import ABCMeta
from abc import abstractmethod
class Base(six.with_metaclass(ABCMeta)):
def __init__(self):
print('Init abstract base')
@abstractmethod
def do_something(self):
pass
class Subclass(Base):
def __init__(self):
super(Subclass, self).__init__()
def do_something(self):
print('Done.')
sub = Subclass()
sub.do_something()
但是,如果我让 Base
class 简单地继承自 object
,并且只在需要时使用装饰器,我注意到行为没有变化。
from abc import abstractmethod
class Base(object):
def __init__(self):
print('Init abstract base')
@abstractmethod
def do_something(self):
pass
class Subclass(Base):
def __init__(self):
super(Subclass, self).__init__()
def do_something(self):
print('Done.')
sub = Subclass()
sub.do_something()
我发现即使在更复杂的架构上也是如此,所以我想知道:后一种方法什么时候会失败?
您没有看到任何区别,因为您的第一个子class 确实实现了do_something
抽象方法。
在两个版本的子classes中注释掉do_something
的定义,你会发现在第一种情况下你在尝试实例化时得到了TypeError
subclass - 你还会得到一个试图实例化第一个版本 Base
class 本身的 FWIW。使用第二个版本,您可以实例化两个 classes(这应该是不可能的,因为它们是抽象的)并调用抽象的 do_something
方法——这违背了 ABC 的要点之一。
您还会错过 ABC FWIW 的许多其他有趣功能...
PEP 3119 指出:
The
@abstractmethod
decorator should only be used inside a class body, and only for classes whose metaclass is (derived from)ABCMeta
. Dynamically adding abstract methods to a class, or attempting to modify the abstraction status of a method or class once it is created, are not supported.
但是,我找不到原因的解释。具体来说,我没有注意到在未明确继承自 ABCMeta
的 class 中仅使用 @abstractmethod
时的行为差异。在下面这个简单的例子中,如果我理解正确的话,正确的做法是:
import six
from abc import ABCMeta
from abc import abstractmethod
class Base(six.with_metaclass(ABCMeta)):
def __init__(self):
print('Init abstract base')
@abstractmethod
def do_something(self):
pass
class Subclass(Base):
def __init__(self):
super(Subclass, self).__init__()
def do_something(self):
print('Done.')
sub = Subclass()
sub.do_something()
但是,如果我让 Base
class 简单地继承自 object
,并且只在需要时使用装饰器,我注意到行为没有变化。
from abc import abstractmethod
class Base(object):
def __init__(self):
print('Init abstract base')
@abstractmethod
def do_something(self):
pass
class Subclass(Base):
def __init__(self):
super(Subclass, self).__init__()
def do_something(self):
print('Done.')
sub = Subclass()
sub.do_something()
我发现即使在更复杂的架构上也是如此,所以我想知道:后一种方法什么时候会失败?
您没有看到任何区别,因为您的第一个子class 确实实现了do_something
抽象方法。
在两个版本的子classes中注释掉do_something
的定义,你会发现在第一种情况下你在尝试实例化时得到了TypeError
subclass - 你还会得到一个试图实例化第一个版本 Base
class 本身的 FWIW。使用第二个版本,您可以实例化两个 classes(这应该是不可能的,因为它们是抽象的)并调用抽象的 do_something
方法——这违背了 ABC 的要点之一。
您还会错过 ABC FWIW 的许多其他有趣功能...