2011-10-13 5 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

これは特殊なケースです。オブジェクトをサブクラス化せずに拡張する必要がある場合があります。メソッドの1つを単にオーバーライドできるかどうか、または既存のオーバーライドメソッドを保持する必要があるかどうかをチェックする必要があります。したがって、デバッグ/解析目的ではないにしても、それはオブジェクトインスペクタです。 これは必ずしも良い考えではないかもしれませんが、この場合は正当だと思います。考えられる設計上の欠陥を指摘してくれてありがとう。 –

0

ハムステルゲンの解答を拡大する。クラスは基本クラスをクラス変数__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

一般的な方法は、(のpython 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

、あなたは、メソッドresulution順序リストを返し、メソッドmro()を持っています。 [0]はクラスそのものです。

だから、だから、eggsを新たに定義されて

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

を行うことができます。

>>> 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が継承されます。

これらを使用すると、独自のヒューリスティックを作成できます。

関連する問題