提问人:Jesse Aldridge 提问时间:6/7/2009 最后编辑:jamylakJesse Aldridge 更新时间:7/23/2023 访问量:84379
获取定义方法的类
Get class that defined 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'
meth.__qualname__
感谢 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__
只是给你一个实例,它绑定到那个特定的实例。它类似于 .如果有 ,将为您提供一个实例,而不是实例。OP 想要的是得到 ,似乎只有像 Martelli 那样通过步行 MRO @Alex才能获得。Cls
meth
Cls().meth.im_class
class SCls(Cls)
SCls().meth.__self__
SCls
Cls
Cls
我尝试做类似的事情来检查基类中的存根方法是否已在子类中实现。无论我尝试哪种方式,我都无法检测到中间类何时实际实现该方法(下面的情况)。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
P.S.:这并不能直接回答这个问题......恕我直言,人们想知道哪个类定义了方法有两个主要原因;一种是指向调试代码中的类(例如在异常处理中),另一种是确定方法是否已重新实现(其中 method 是程序员要实现的存根)。这个答案以不同的方式解决了第二种情况。
评论
pprint(self.method)
我不知道为什么没有人提出这个问题,或者为什么最高答案在速度慢得要命时有 50 个赞成票,但你也可以做到以下几点:
def get_class_that_defined_method(meth):
return meth.im_class.__name__
对于 python 3,我相信这发生了变化,您需要研究..__qualname__
评论
meth.__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
Python 3 (英语)
以一种非常简单的方式解决了它:
str(bar.foo_method).split(" ", 3)[-2]
这给了
'FooClass.foo_method'
在点上拆分以分别获取类和函数名称
评论
bar.foo_method.__qualname__
'FooClass.foo_method
我发现__qualname__在 Python3 中很有用。
我是这样测试的:
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'
测试结束后,我在这里找到了另一个答案。
如果收到此错误:
'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)
Python 3 的另一种解决方案:
class FooClass:
def foo_method(self):
print("foo")
class BarClass(FooClass):
pass
class BazClass(BarClass):
pass
baz = BazClass()
tmp = baz.foo_method.__self__.__class__
while hasattr(tmp.__base__, "foo_method"):
tmp = tmp.__base__
print("defining class: {}".format(tmp))
tmp().foo_method()
输出:
defining class: <class '__main__.FooClass'>
foo
Python 2.7 或 3:
class FooClass:
def foo_method(self):
print("foo")
class BarClass(FooClass):
pass
class BazClass(BarClass):
pass
baz = BazClass()
tmp = baz.foo_method.__self__.__class__
while len(tmp.__bases__) > 0 and hasattr(tmp.__bases__[0], "foo_method"):
tmp = tmp.__bases__[0]
print("defining class: {}".format(tmp))
tmp().foo_method()
我们可以使用方法解析顺序或从中查找名称,它有:mro()
SomeClass
some_method
class SomeClass:
def __init__(self):
self.foo = 100
def some_method(self):
return self.foo
a = SomeClass()
print(a.some_method.__self__.__class__.mro()[0])
输出:
<class '__main__.SomeClass'>
这样我们就可以找到所属类的名称,即使它继承了:some_method
SomeOtherClass
class SomeClass:
def __init__(self):
self.foo = 100
def some_method(self):
return self.foo
class SomeOtherClass(SomeClass):
def __init__(self):
super().__init__()
self.other_foo = 1
def some_other_method(self):
return self.other_foo
a = SomeOtherClass()
print([cls for cls in a.some_method.__self__.__class__.mro() if cls.__dict__.__contains__(a.some_method.__name__)][0])
print([cls for cls in a.some_other_method.__self__.__class__.mro() if cls.__dict__.__contains__(a.some_other_method.__name__)][0])
输出:
<class '__main__.SomeClass'>
<class '__main__.SomeOtherClass'>
或具有 (或) 的所有类的名称:some_method
some_other_method
print([cls for cls in a.some_method.__self__.__class__.mro() if hasattr(cls, a.some_method.__name__)])
print([cls for cls in a.some_other_method.__self__.__class__.mro() if hasattr(cls, a.some_other_method.__name__)])
输出:
[<class '__main__.SomeOtherClass'>, <class '__main__.SomeClass'>]
[<class '__main__.SomeOtherClass'>]
要获得 ing 中的 s,请执行以下操作:__name__
str
print([cls.__name__ ...
只需使用属性即可__qualname__
ClassOrInstance.method.__qualname__
生成一个字符串Class.method
代码,经测试使用Python 3.8.8
class Grandparent:
def test(self):
print("grandparent")
class Parent(Grandparent):
def test(self):
print("parent")
class Child(Parent):
pass
class Uncle(Grandparent):
pass
>>> Grandparent().test.__qualname__
'Grandparent.test'
>>> Parent().test.__qualname__
'Parent.test'
>>> Child().test.__qualname__
'Parent.test'
>>> Uncle().test.__qualname__
'Grandparent.test'
下一步
如果要检查代码中的实现位置,可以执行以下操作
>>> Uncle.test.__qualname__.split(".")[0] == Grandparent.__name__
True
>>> Child.test.__qualname__.split(".")[0] == Grandparent.__name__
False
>>> Child.test.__qualname__.split(".")[0] == Parent.__name__
True
这里演示的是 a 而不是 .class
instance
inspect._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
从 Python 3.6 开始,您已经能够用作描述符的钩子,如本次对该问题的重复回答中所述。__set_name__
评论