メソッドを定義したクラスを取得する
-
12-09-2019 - |
質問
Python でメソッドを定義したクラスを取得するにはどうすればよいですか?
次の例を出力したいと思います。__main__.FooClass
":
class FooClass:
def foo_method(self):
print "foo"
class BarClass(FooClass):
pass
bar = BarClass()
print get_class_that_defined_method(bar.foo_method)
解決
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
他のヒント
要点を見逃していたことを指摘してくれた Sr2222 に感謝します...
これは、Alex のものと同様の修正されたアプローチですが、何もインポートする必要はありません。ただし、このアプローチは、継承全体を返すのではなく、定義クラスが見つかるとすぐに停止するため、継承クラスの巨大な階層がない限り、これが改善だとは思いません。 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
Alex ソリューションは同じ結果を返します。Alex のアプローチが使用できる限り、これの代わりにそれを使用します。
私は、誰もこれを育てていない理由を知っていないか、それは地獄のように遅いとき、トップの答えは50 upvotesを持っていますが、あなたはまた、次の操作を行うことができる理由ます:
def get_class_that_defined_method(meth):
return meth.im_class.__name__
のpython 3のために私はこれを変更し、あなたが.__qualname__
を検討する必要があります信じています。
私は、基本クラスのメソッドはサブクラスで実装かされていた時はいつでも、基本的な考え方をチェックして、やや似て何かを開始しました。中間クラスが実際にメソッドを実装したとき、私は検出できなかった私はもともとそれをやった方法を判明ます。
それのための私の回避策は実際には非常に簡単でした。メソッドの属性を設定するを後にその存在をテストします。ここでは全部の簡素化があります:
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:実は(?精神ということではありません)method()
からrun_method()
を呼び出すと、それは方法に変更されていないすべての引数を渡す必要があります。
P.S:この答えは、直接の質問に答えていません。私見1のメソッドを定義したクラスを知りたいでしょう二つの理由があります。最初(例えば例外処理のように)デバッグコードにおけるクラスに指を指すようになり、第二の方法は、再実装されている場合(この方法は、プログラマによって実装されることを意味スタブである)を決定することです。この答えは、別の方法で、第2のケースを解決します。
はPython 3では、あなたが実際のクラスオブジェクトが必要な場合はあなたが行うことができます:
import sys
f = Foo.my_function
vars(sys.modules[f.__module__])[f.__qualname__.split('.')[0]] # Gets Foo object
関数が入れ子になったクラスに属している可能性がある場合、次のようにあなたが反復する必要があります。
f = Foo.Bar.my_function
vals = vars(sys.modules[f.__module__])
for attr in f.__qualname__.split('.')[:-1]:
vals = vals[attr]
# vals is now the class Foo.Bar