获取定义方法的类

2025-03-04 08:24:00
admin
原创
90
摘要:问题描述:如何获取在 Python 中定义某个方法的类?我想要以下示例打印“ __main__.FooClass”:class FooClass: def foo_method(self): print "foo" class BarClass(FooClass)...

问题描述:

如何获取在 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)

解决方案 1:

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

解决方案 2:

我不知道为什么没有人提出这个问题,或者为什么在速度非常慢的情况下最佳答案有 50 个赞成票,但您也可以执行以下操作:

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

对于 python 3,我相信这已经发生了变化,您需要研究一下.__qualname__

解决方案 3:

在 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

解决方案 4:

感谢 Sr2222 指出我没有抓住重点...

这是更正后的方法,与 Alex 的方法类似,但不需要导入任何内容。不过,我认为这不算是一种改进,除非继承类的层次结构非常庞大,因为这种方法在找到定义类后就会停止,而不是像getmroAlex 那样返回整个继承。如前所述,这种情况不太可能发生。

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 方法,我就会使用它而不是这个。

解决方案 5:

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

经过我的测试,我在这里找到了另一个答案。

解决方案 6:

如果你收到此错误:

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

解决方案 7:

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

')

    class_method()
    print(inspect._findclass(class_method), end='

')

    print('unbound method')
    print(inspect._findclass(unbound_method), end='

')

    bound_method()
    print(inspect._findclass(bound_method), end='

')

    glbl_func()
    print(inspect._findclass(glbl_func), end='

')

    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

解决方案 8:

Python 3

用一个非常简单的方法解决了它:

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

这给出

'FooClass.foo_method'

按点拆分,分别获取类和函数名称

解决方案 9:

我尝试做类似的事情来检查基类中的存根方法是否已在子类中实现。无论我尝试哪种方法,我都无法检测中间类何时真正实现该方法(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

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

解决方案 10:

从 Python 3.6 开始,您已经能够将其用作__set_name__描述符上的钩子,如对该问题重复的回答中所述。

解决方案 11:

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

解决方案 12:

我们可以使用方法解析顺序或从中找到它的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__s str

print([cls.__name__ ...

解决方案 13:

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

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   3975  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   2742  
  本文介绍了以下10款项目管理软件工具:禅道项目管理软件、Freshdesk、ClickUp、nTask、Hubstaff、Plutio、Productive、Targa、Bonsai、Wrike。在当今快速变化的商业环境中,项目管理已成为企业成功的关键因素之一。然而,许多企业在项目管理过程中面临着诸多痛点,如任务分配不...
项目管理系统   80  
  本文介绍了以下10款项目管理软件工具:禅道项目管理软件、Monday、TeamGantt、Filestage、Chanty、Visor、Smartsheet、Productive、Quire、Planview。在当今快速变化的商业环境中,项目管理已成为企业成功的关键因素之一。然而,许多项目经理和团队在管理复杂项目时,常...
开源项目管理工具   88  
  本文介绍了以下10款项目管理软件工具:禅道项目管理软件、Smartsheet、GanttPRO、Backlog、Visor、ResourceGuru、Productive、Xebrio、Hive、Quire。在当今快节奏的商业环境中,项目管理已成为企业成功的关键因素之一。然而,许多企业在选择项目管理工具时常常面临困惑:...
项目管理系统   77  
热门文章
项目管理软件有哪些?
曾咪二维码

扫码咨询,免费领取项目管理大礼包!

云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用