2011-10-13 124 views
8

我想告訴除了重載或新定義的方法之外的繼承方法。這可能與Python?有沒有辦法在Python中識別繼承的方法?

實施例:

class A(object): 
    def spam(self): 
    print 'A spam' 
    def ham(self): 
    print 'A ham' 

class B(A): 
    def spam(self): 
    print 'Overloaded spam' 
    def eggs(self): 
    print 'Newly defined eggs' 

期望的功能:

>>> magicmethod(B.spam) 
'overloaded' 
>>> magicmethod(B.ham) 
'inherited' 
>>> magicmethod(B.eggs) 
'newly defined' 

是否有「魔術方法」像在本例中,或一些方式告訴那些類型的方法實現開的?

回答

12

我不確定這是個好主意,但您可以使用hasattr__dict__來做到這一點。

def magicmethod(clazz, method): 
    if method not in clazz.__dict__: # Not defined in clazz : inherited 
     return 'inherited' 
    elif hasattr(super(clazz), method): # Present in parent : overloaded 
     return 'overloaded' 
    else: # Not present in parent : newly defined 
     return 'newly defined' 
7

如果你知道的祖先,你可以簡單的測試:

>>> B.spam == A.spam 
False 
>>> B.ham == A.ham 
True 

,並找到所有的基類的列表,看看這裏:List all base classes in a hierarchy of given class?

我也應指出的是,如果你需要這個,你一流的設計可能是錯誤的。你不應該在意OOP中的這些東西(除非你正在創建一個對象檢查器或類似的東西)。

+0

好的呼叫,這是一個奇怪的要求在OOP – Pengman

+0

這是一個特殊的情況下,一個對象可能不得不被擴展的子類。我必須檢查我是否可以簡單地重寫其中一種方法,或者是否必須保留現有的重寫方法。所以是的,儘管不是用於調試/分析的目的,它仍然是一種對象檢查器。 我意識到這可能並不總是一個好主意,但我認爲在這種情況下是合理的。感謝您指出可能的設計缺陷。 –

0

擴展在hamstergene的答案;一個類將其基類存儲在類變量__bases__中。

所以:

>>> B.spam == B.__bases__[0].spam 
False 
>>> B.ham == B.__bases__[0].ham 
True 
>>> B.eggs == B.__bases__[0].eggs 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
AttributeError: type object 'A' has no attribute 'eggs' 
>>> hasattr(B,"eggs") 
True 
>>> hasattr(B.__bases__[0],"eggs") 
False 
6

一般的方式將是(蟒蛇2 *):

def _getclass(method): 
    try: 
     return method.im_class 
    except AttributeError: 
     return method.__class__ 

def magicmethod(method): 
    method_cls = _getclass(method) 
    if method.__name__ not in method_cls.__dict__: 
     return 'inherited' 
    for cls in method_cls.__mro__[1:]: 
     if method.__name__ in cls.__dict__: 
      return 'overloaded' 
    return 'newly defined' 


__test__ = {"example": """ 

    >>> class A(object): 
    ...  def spam(self): 
    ...   print 'A spam' 
    ...  def ham(self): 
    ...   print 'A ham' 

    >>> class B(A): 
    ...  def spam(self): 
    ...   print 'Overloaded spam' 
    ...  def eggs(self): 
    ...   print 'Newly defined eggs' 

    >>> magicmethod(B.spam) 
    'overloaded' 
    >>> magicmethod(B.ham) 
    'inherited' 
    >>> magicmethod(B.eggs) 
    'newly defined' 
    >>> magicmethod(B.__init__) 
    'inherited' 
"""} 
0

對於新樣式類,你有一個方法mro(),返回的方法resulution順序列表。 [0]本身就是這個類。

所以,你可以做

>>> any(hasattr(i, 'ham') for i in B.mro()[1:]) 
True 
>>> any(hasattr(i, 'spam') for i in B.mro()[1:]) 
True 
>>> any(hasattr(i, 'eggs') for i in B.mro()[1:]) 
False 

所以eggs被重新定義。

>>> any(getattr(B, 'ham') == getattr(i, 'ham', None) for i in B.mro()[1:]) 
True 
>>> any(getattr(B, 'spam') == getattr(i, 'spam', None) for i in B.mro()[1:]) 
False 

所以ham被繼承。

有了這些,你可以制定自己的啓發式。

相關問題