2009-06-07 3 views
52

Pythonでメソッドを定義したクラスを取得するにはどうすればよいですか?私はポイントを逃した指摘してメソッドを定義したクラスを取得する

class FooClass: 
    def foo_method(self): 
     print "foo" 

class BarClass(FooClass): 
    pass 

bar = BarClass() 
print get_class_that_defined_method(bar.foo_method) 
+0

使用しているPythonのバージョンは? 2.2より前のバージョンでは、im_classを使用することができましたが、バインドされたselfオブジェクトのタイプを示すように変更されました。 –

+1

お役立ち情報しかし私は2.6を使用しています。 –

答えて

54
import inspect 

def get_class_that_defined_method(meth): 
    for cls in inspect.getmro(meth.im_class): 
     if meth.__name__ in cls.__dict__: 
      return cls 
    return None 
+0

それは、ありがとう! –

+0

あなたはようこそ! –

+1

ありがとう、それは私自身でこれを理解するためにしばらく時間がかかりました – David

5

おかげSr2222 ...

ここで修正アプローチがあります:

私は「__main__.FooClass」を印刷するには、次の例をしたいと思いますアレックスのようなものですが、何かを輸入する必要はありません。 getmroのように全体の継承を返すのではなく、定義したクラスが見つかると直ちにこのアプローチが停止するので、継承されたクラスの巨大な階層がない限り、それは改善だとは思わない。前述のように、これは非常にです。

def get_class_that_defined_method(method): 
    method_name = method.__name__ 
    if method.__self__:  
     classes = [method.__self__.__class__] 
    else: 
     #unbound method 
     classes = [method.im_class] 
    while classes: 
     c = classes.pop() 
     if method_name in c.__dict__: 
      return c 
     else: 
      classes = list(c.__bases__) + classes 
    return None 

そして例:

>>> class A(object): 
...  def test(self): pass 
>>> class B(A): pass 
>>> class C(B): pass 
>>> class D(A): 
...  def test(self): print 1 
>>> class E(D,C): pass 

>>> get_class_that_defined_method(A().test) 
<class '__main__.A'> 
>>> get_class_that_defined_method(A.test) 
<class '__main__.A'> 
>>> get_class_that_defined_method(B.test) 
<class '__main__.A'> 
>>> get_class_that_defined_method(C.test) 
<class '__main__.A'> 
>>> get_class_that_defined_method(D.test) 
<class '__main__.D'> 
>>> get_class_that_defined_method(E().test) 
<class '__main__.D'> 
>>> get_class_that_defined_method(E.test) 
<class '__main__.D'> 
>>> E().test() 
1 

アレックス・ソリューションは、同じ結果を返します。アレックスのアプローチが使用できる限り、私はこれの代わりにそれを使用します。

+0

'Cls()。meth .__ self__'は' meth 'のその特定のインスタンスにバインドされている 'Cls'のインスタンスを提供します。 'Cls()。meth.im_class'に似ています。あなたが 'class SCls(Cls)'を持っているなら、 'SCls()。meth .__ self__'は' Clls'インスタンスではなく 'SCls'インスタンスを取得します。 OPが望んでいるのは 'Cls'を手に入れることです。それは@Alex MartelliのようにMROを歩くことによってのみ利用可能です。 –

+0

@ sr2222そうです。私はアレックスのソリューションがよりコンパクトだとは思っていますが、私がすでに始めているように答えを修正しました。 – estani

+0

輸入を避ける必要がある場合は良い解決策ですが、基本的にMROを再実装するだけなので、永遠に動作することは保証されません。 MROはおそらく同じままですが、Pythonの過去にはすでに変更されていましたが、再度変更された場合、このコードは微妙で広範なバグになります。 –

1

私はやや似たようなことをやり始めましたが、基本的には基本クラスのメソッドが実装されたかどうかをチェックすることでした。私が最初にやったやり方は、中間のクラスが実際にこのメソッドを実装していたときには検出できませんでした。

私の回避策は実際にはとても簡単でした。メソッドを設定し、後でその存在をテストします。ここでは全部の簡素化です:

class A(): 
    def method(self): 
     pass 
    method._orig = None # This attribute will be gone once the method is implemented 

    def run_method(self, *args, **kwargs): 
     if hasattr(self.method, '_orig'): 
      raise Exception('method not implemented') 
     self.method(*args, **kwargs) 

class B(A): 
    pass 

class C(B): 
    def method(self): 
     pass 

class D(C): 
    pass 

B().run_method() # ==> Raises Exception: method not implemented 
C().run_method() # OK 
D().run_method() # OK 

UPDATE:実際に(?ということは精神ではありません)run_method()からmethod()を呼び出すと、それは方法に変更されていないすべての引数を渡すことがあります。

P .:この回答は直接質問に答えません。どのクラスがメソッドを定義したのかを知りたいのは2つの理由があります。 (例外ハンドリングのような)デバッグコードでクラスの指を指すことです.2番目は、メソッドが再実装されたかどうかを判断することです(メソッドはプログラマによって実装されることを意図したスタブです)。この答えは、その別の方法で別のケースを解決します。

2

私は、誰もこれを育てていない理由を知っていないか、それは地獄のように遅い場合、トップの答えは50 upvotesを持っていますが、あなたも行うことができる理由次のPython 3用

def get_class_that_defined_method(meth): 
    return meth.im_class.__name__ 

私はこれが変わったと信じて、.__qualname__を調べる必要があります。

関連する問題