2016-12-15 30 views
3

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

@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 abstractmethod。

在这两个版本的子类中注释掉do_something的定义,你会发现在第一种情况下,当你尝试实例化子类时会得到一个TypeError - 你还会得到一个尝试实例化第一个版本Base本身FWIW。在第二个版本中,你可以对两个类进行实例化(因为这些类是抽象的,所以不应该是可能的),并且调用抽象的do_something方法 - 哪种方法会击败ABC的一个要点。

您还会错过ABCs FWIW的其他一些有趣功能...

相关问题