2016-12-15 59 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的其他一些有趣功能...

相關問題