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)
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
__dict__
!時々__slots__
使用されます。getattr
メソッドがクラスにあるかどうかをテストするために使用する方がおそらく良いでしょう。
'function' object has no attribute 'im_class'
私が要点を逃していたことを指摘してくれた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ソリューションは同じ結果を返します。アレックスのアプローチが使用できる限り、私はこれの代わりにそれを使用します。
Cls().meth.__self__
のCls
特定のインスタンスにバインドされているインスタンスを提供するだけですmeth
。に類似していCls().meth.im_class
ます。を持っている場合はclass SCls(Cls)
、インスタンスではなくインスタンスSCls().meth.__self__
を取得SCls
しCls
ます。OPが望んでいるのは、取得することですCls
。これは、@ AlexMartelliのようにMROを歩くことによってのみ利用できるようです。
なぜ誰もこれを提起したことがないのか、それが地獄のように遅いのにトップアンサーが50の賛成票を持っているのかはわかりませんが、次のこともできます。
def get_class_that_defined_method(meth):
return meth.im_class.__name__
Python 3の場合、これは変更されたと思います.__qualname__
。調査する必要があります。
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
私はやや似たようなことを始めました。基本的には、基本クラスのメソッドがサブクラスに実装されているかどうかをチェックするという考え方でした。当初のやり方で、中間クラスが実際にメソッドを実装しているのはいつか検出できませんでした。
それに対する私の回避策は実際には非常に簡単でした。メソッド属性を設定し、後でその存在をテストします。全体を簡略化すると、次のようになります。
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
更新:実際にmethod()
fromを呼び出しrun_method()
(それは精神ではありませんか?)、すべての引数を変更せずにメソッドに渡します。
PS:この答えは質問に直接答えるものではありません。私見では、どのクラスがメソッドを定義したかを知りたい理由が2つあります。1つ目は、デバッグコード(例外処理など)でクラスを指さし、2つ目は、メソッドが再実装されているかどうかを判断することです(メソッドはプログラマーが実装することを目的としたスタブです)。この答えは、その2番目のケースを別の方法で解決します。
非常に簡単な方法でそれを解決しました:
str(bar.foo_method).split(" ", 3)[-2]
これは与える
'FooClass.foo_method'
ドットで分割して、クラスと関数名を別々に取得します