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

Pie*_*esi 8 python inheritance abstract-class abc python-decorators

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()
Run Code Online (Sandbox Code Playgroud)

但是,如果我让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()
Run Code Online (Sandbox Code Playgroud)

我发现即使在更复杂的架构上也是如此,所以我想知道:后一种方法什么时候会失败?

bru*_*ers 3

您看不到任何区别,因为您的第一个子类确实实现了do_something抽象方法。

注释掉两个版本中子类中的定义do_something,您会发现在第一种情况下,TypeError当尝试实例化子类时,您会得到一个 - 您还会得到一个尝试实例化第一个版本Base类本身的FWIW。在第二个版本中,您可以实例化这两个类(这应该是不可能的,因为它们是抽象的)并调用抽象do_something方法 - 这违背了 ABC 的要点之一。

您还会错过 ABC FWIW 的许多其他有趣功能......