如何在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
测试方法是否在类中。 - Codie CodeMonkeymeth.__qualname__
有什么问题吗? - Marc我不知道为什么没有人提到过这个问题,或者为什么最佳答案得到了50个赞,因为它实在太慢了,但你也可以尝试以下方法:
def get_class_that_defined_method(meth):
return meth.im_class.__name__
我认为对于Python 3,这个已经改变了,你需要查看.__qualname__
。
meth.__qualname__
可以获取方法的限定名称,其中包括定义该方法的类的名称。 - Princy在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
感谢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的方法,我会使用它而不是这个。
Cls().meth.__self__
只会给你绑定到特定实例的 meth
的 Cls
实例。这类似于 Cls().meth.im_class
。如果你有 class SCls(Cls)
,SCls().meth.__self__
将会得到一个 SCls
实例,而不是一个 Cls
实例。OP 想要的是获取 Cls
,似乎只能像 @Alex Martelli 一样遍历 MRO 来实现。 - Silas Rayim_class
是仅适用于Python 2的属性,因此这在Python 3中无法使用未绑定方法(它们只是常规函数)。 - Anakhand我发现在Python3中__qualname__很有用。
我像这样测试它:
class Cls(object):
def func(self):
print('1')
c = Cls()
print(c.func.__qualname__)
# output is: 'Cls.func'
def single_func():
print(2)
print(single_func.__module__)
# output: '__main__'
print(single_func.__qualname__)
# output: 'single_func'
在我的测试中,我发现这里有另一个答案。
我尝试了类似的方法来检查基类中的存根方法是否在子类中被实现。无论我如何尝试,都无法检测到中间类是否实际上实现了该方法(下面是d.run_method()
的情况)。
最后,我通过设置一个方法属性并在后面测试其存在性来解决了这个问题:
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
附注:这并没有直接回答问题...在我看来,人们想要知道哪个类定义了一个方法的主要原因有两个;一个是在调试代码(例如在异常处理中)时指向一个类,另一个是确定方法是否已被重新实现(其中方法是一个桩,旨在由程序员实现)。这个答案用不同的方式解决了第二种情况。
pprint(self.method)
,它清楚地打印出拥有类,因此数据在某个地方。 - Thomas Guyot-Sionnest以下是一种非常简单的解决方法:
str(bar.foo_method).split(" ", 3)[-2]
这将返回
'FooClass.foo_method'
按照句点分割以单独获取类名和函数名。
bar.foo_method.__qualname__
,得到 'FooClass.foo_method'
。我不知道是否有特殊情况,但它对于当前的问题有效。 - FMcinspect._findclass
对于任何函数/方法似乎都工作正常。
import inspect
import sys
class SomeClass:
@staticmethod
def staticMethod():
print('staticMethod')
@classmethod
def classMethod(cls):
print('classMethod')
def someMethod(self):
print('bound method')
def myGlblFunc():
print('Global function')
if __name__ == '__main__':
static_method = SomeClass.staticMethod
class_method = SomeClass.classMethod
unbound_method = SomeClass.someMethod
bound_method = SomeClass().someMethod
glbl_func = myGlblFunc
static_method()
print(inspect._findclass(static_method), end='\n\n')
class_method()
print(inspect._findclass(class_method), end='\n\n')
print('unbound method')
print(inspect._findclass(unbound_method), end='\n\n')
bound_method()
print(inspect._findclass(bound_method), end='\n\n')
glbl_func()
print(inspect._findclass(glbl_func), end='\n\n')
sys.exit(0)
# Output:
# staticMethod
# <class '__main__.SomeClass'>
#
# classMethod
# <class '__main__.SomeClass'>
#
# unbound method
# <class '__main__.SomeClass'>
#
# bound method
# <class '__main__.SomeClass'>
#
# Global function
# None
如果您遇到此错误:
'function' object has no attribute 'im_class'
import inspect
def get_class_that_defined_method(meth):
class_func_defided = meth.__globals__[meth.__qualname__.split('.')[0]]
#full_func_name = "%s.%s.%s"%(class_func_defided.__module__,class_func_defided.__name__,meth.__name__)
if inspect.isfunction(class_func_defided):
print("%s is not part of a class."%meth.__name__)
return None
return class_func_defided
示例测试:
class ExampleClass:
@staticmethod
def ex_static_method():
print("hello from static method")
def ex_instance_method(self):
print("hello from instance method")
def ex_funct(self):
print("hello from simple function")
if __name__ == "__main__":
static_method_class = get_class_that_defined_method(ExampleClass.ex_static_method)
static_method_class.ex_static_method()
instance_method_class = get_class_that_defined_method(ExampleClass.ex_instance_method)
instance_method_class().ex_instance_method()
function_class = get_class_that_defined_method(ex_funct)