为啥在元类派生自ABCMeta的类中需要使用@abstractmethod?
Posted
技术标签:
【中文标题】为啥在元类派生自ABCMeta的类中需要使用@abstractmethod?【英文标题】:Why does @abstractmethod need to be used in a class whose metaclass is derived from ABCMeta?为什么在元类派生自ABCMeta的类中需要使用@abstractmethod? 【发布时间】:2017-05-01 01:02:18 【问题描述】:PEP 3119 声明:
@abstractmethod
装饰器只能在类体内使用,并且只能用于元类(派生自)ABCMeta
的类。不支持向类动态添加抽象方法,或在方法或类创建后尝试修改其抽象状态。
但是,我无法解释为什么会这样。具体来说,在没有显式继承自ABCMeta
的类中仅使用@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
类简单地从 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()
我发现即使在更复杂的架构上也是如此,所以我想知道:后一种方法什么时候会失败?
【问题讨论】:
【参考方案1】:您看不到任何区别,因为您的第一个子类确实实现了do_something
抽象方法。
在两个版本的子类中注释掉do_something
的定义,您会发现在第一种情况下,在尝试实例化子类时会得到TypeError
- 您还会得到一个尝试实例化的实例第一个版本 Base
类本身 FWIW。在第二个版本中,您可以实例化两个类(因为它们是抽象的,所以这是不可能的)并调用抽象的 do_something
方法——这违背了 ABC 的要点之一。
您还会错过 ABCs FWIW 的许多其他有趣功能...
【讨论】:
您能否详细说明在这种情况下遗漏的其他相关功能?以上是关于为啥在元类派生自ABCMeta的类中需要使用@abstractmethod?的主要内容,如果未能解决你的问题,请参考以下文章