关于python:获取定义方法的类

Get class that defined method

如何获取在Python中定义方法的类?

我希望下面的示例打印"__main__.FooClass":

1
2
3
4
5
6
7
8
9
class FooClass:
    def foo_method(self):
        print"foo"

class BarClass(FooClass):
    pass

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


1
2
3
4
5
6
7
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指出我错过了要点…

这是正确的方法,和亚历克斯的方法一样,但不需要导入任何内容。不过,我不认为这是一种改进,除非在找到定义类后,继承类的层次结构非常庞大,因为这种方法会立即停止,而不是像getmro那样返回整个继承。如前所述,这是一个非常不可能的情况。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
>>> 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解决方案返回相同的结果。只要亚历克斯的方法可以使用,我会使用它而不是这个。


我不知道为什么没有人提出过这个问题,也不知道为什么当速度慢得像地狱一样时,最上面的答案有50个赞成票,但是你也可以做以下的事情:

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

对于python 3,我相信这已经改变了,您需要研究.__qualname__


我开始做一些类似的事情,基本上,只要基类中的一个方法已经实现或者不在子类中,这个想法就是检查。原来我是这样做的,当一个中间类实际实现该方法时,我无法检测到。

实际上,我对它的解决方法相当简单:设置一个方法属性并稍后测试它的存在。以下是整个过程的简化:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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

更新:实际上从run_method()调用method()(这不是精神吗?)并让它将所有未修改的参数传递给该方法。

附言:这个答案不能直接回答问题。imho有两个原因,一个是想知道哪个类定义了一个方法;第一个是指调试代码中的一个类(例如在异常处理中),第二个是确定该方法是否被重新实现(其中,方法是一个由程序员实现的存根)。这个答案以不同的方式解决了第二个问题。


在Python3中,如果需要实际的类对象,可以执行以下操作:

1
2
3
import sys
f = Foo.my_function
vars(sys.modules[f.__module__])[f.__qualname__.split('.')[0]]  # Gets Foo object

如果函数可以属于嵌套类,则需要按如下方式迭代:

1
2
3
4
5
f = Foo.Bar.my_function
vals = vars(sys.modules[f.__module__])
for attr in f.__qualname__.split('.'):
    vals = vals[attr]
# vals is now the class Foo.Bar