为什么@abstractmethod需要在其元类派生自ABCMeta的类中使用?

时间:2016-12-15 12:14:49

标签: python inheritance abstract-class python-decorators abc

PEP 3119声明:

  

@abstractmethod装饰器只应在类体内使用,并且仅适用于其元类是(派生自)ABCMeta的类。不支持动态地将抽象方法添加到类中,或者尝试在创建方法或类时修改其抽象状态。

但是,我无法找到解释原因的原因。具体来说,我没有注意到在未明确继承@abstractmethod的类中仅使用ABCMeta时的行为差异。在下面的简单示例中,如果我理解正确,正确的做法是:

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 个答案:

答案 0 :(得分:1)

您没有看到任何差异,因为您的第一个子类确实实现了do_something abstractmethod。

在两个版本的子类中注释掉do_something的定义,你会发现在第一种情况下,当你试图实现子类时,你得到一个TypeError - 你也会得到一个试图实现第一个版本Base类本身的FWIW。使用第二个版本,您可以实现两个类(这不应该是可能的,因为它们是抽象的)并调用抽象的do_something方法 - 哪种方法会破坏ABCs的一个主要点。

你也会错过ABC FWIW的其他一些有趣的功能......