9

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()

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

4

1 回答 1

3

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

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

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

于 2016-12-15T12:54:04.207 回答