获取定义方法的类

问题描述 投票:0回答:11

如何获取在 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 python-2.6 python-datamodel
11个回答
81
投票
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

13
投票

我不知道为什么从来没有人提出这个问题,或者为什么最慢的答案有 50 个赞成票,但你也可以执行以下操作:

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

对于 python 3,我相信这发生了变化,您需要研究

.__qualname__
.


9
投票

在 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

8
投票

感谢 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 的方法,我都会用它来代替这个。


3
投票

我发现 __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'

测试后,我找到了另一个答案here.


2
投票

蟒蛇3

用非常简单的方式解决了它:

str(bar.foo_method).split(" ", 3)[-2]

这给

'FooClass.foo_method'

在点上拆分,分别得到类名和函数名


2
投票

我尝试做类似的事情来检查基类中的存根方法是否已在子类中实现。无论我尝试哪种方式,我都无法检测到中间类何时实际实现该方法(下面的

d.run_method()
案例)。

我终于通过设置一个方法attribute并稍后测试它的存在来做到了:

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.:这并没有直接回答问题……恕我直言,人们想知道哪个类定义了一个方法有两个主要原因;一种是指责调试代码中的某个类(例如在异常处理中),另一种是确定该方法是否已被重新实现(其中方法是一个存根,旨在由程序员实现)。这个答案以不同的方式解决了第二种情况。


1
投票

如果你得到这个错误:

'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)

1
投票

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()

1
投票

我们可以使用方法解析顺序或

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'>]

要在

__name__
ing中获得
str
s:

print([cls.__name__ ...

0
投票

只需使用
__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

这里演示了一个

class
而不是一个
instance

© www.soinside.com 2019 - 2024. All rights reserved.