获取定义方法的类

发布于 2024-07-24 07:27:06 字数 273 浏览 3 评论 0原文

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

How can I get the class that defined a method in Python?

I'd want the following example to print "__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)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(13

丑丑阿 2024-07-31 07:27:06
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
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
九八野马 2024-07-31 07:27:06

我不知道为什么没有人提出这个问题,也不知道为什么当它慢得要命时,最上面的答案有 50 个赞成票,但你也可以执行以下操作:

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

对于 python 3,我相信这发生了变化,你需要看看进入 .__qualname__

I don't know why no one has ever brought this up or why the top answer has 50 upvotes when it is slow as hell, but you can also do the following:

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

For python 3 I believe this changed and you'll need to look into .__qualname__.

千里故人稀 2024-07-31 07:27:06

在 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

In Python 3, if you need the actual class object you can do:

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

If the function could belong to a nested class you would need to iterate as follows:

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
陪我终i 2024-07-31 07:27:06

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

Thanks Sr2222 for pointing out I was missing the point...

Here's the corrected approach which is just like Alex's but does not require to import anything. I don't think it's an improvement though, unless there's a huge hierarchy of inherited classes as this approach stops as soon as the defining class is found, instead of returning the whole inheritance as getmro does. As said, this is a very unlikely scenario.

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

And the Example:

>>> 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 solution returns the same results. As long as Alex approach can be used, I would use it instead of this one.

童话里做英雄 2024-07-31 07:27:06

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

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

I found __qualname__ is useful in Python3.

I test it like that:

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'

After my test, I found another answer here.

霓裳挽歌倾城醉 2024-07-31 07:27:06

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

inspect._findclass seems to be working fine for any function/method.

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
七颜 2024-07-31 07:27:06

Python 3

以非常简单的方式解决了这个问题:

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

这给出了

'FooClass.foo_method'

分割点上分别获取类和函数名

Python 3

Solved it in a very simple way:

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

This gives

'FooClass.foo_method'

Split on the dot to get the class and the function name separately

缪败 2024-07-31 07:27:06

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

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

I tried doing something similar to check if a stub method in a base class had been implemented or not in a subclass. Whichever way I tried I could not detect when an intermediate class was actually implementing the method (d.run_method() case below).

I finally did it by setting a method attribute and testing its presence later:

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.: This doesn't answer directly the question... IMHO there are two major reasons one would want to know which class defined a method; one is to point fingers at a class in debug code (such as in exception handling), and another is to determine if the method has been re-implemented (where method is a stub meant to be implemented by the programmer). This answer solves that second case in a different way.

戏舞 2024-07-31 07:27:06

从Python 3.6开始,您就可以使用__set_name__作为描述符上的挂钩,如在此答案中所述复制此问题

Since Python 3.6, you have been able to use __set_name__ as a hook on a descriptor, as described in this answer to a duplicate of this question.

稚气少女 2024-07-31 07:27:06

如果您收到此错误:

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

if you get this error:

'function' object has no attribute 'im_class'

try this:

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

sample test:

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)
甜警司 2024-07-31 07:27:06

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

Another solution for 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()

Output:

defining class: <class '__main__.FooClass'>
foo

Python 2.7 or 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()
苏别ゝ 2024-07-31 07:27:06

我们可以使用方法解析顺序或 mro()some_method 中查找 SomeClass 的名称,它具有:

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

获取 str 中的 __name__

print([cls.__name__ ...

We can use method resolution order or mro() to find the name of SomeClass from some_method it has:

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

Outputs:

<class '__main__.SomeClass'>

that way we can find the name of the class that some_method belongs to even if it's inherited by 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])

Outputs:

<class '__main__.SomeClass'>
<class '__main__.SomeOtherClass'>

or the names of all the classes that have some_method (or 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__)])

Outputs:

[<class '__main__.SomeOtherClass'>, <class '__main__.SomeClass'>]
[<class '__main__.SomeOtherClass'>]

To get the __name__s in string:

print([cls.__name__ ...
时常饿 2024-07-31 07:27:06

只需使用 __qualname__ 属性

ClassOrInstance.method.__qualname__ 即可生成 Class.method 字符串

代码,使用 Python 3.8.8 进行测试code>

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

simply use the __qualname__ attribute

ClassOrInstance.method.__qualname__ yields a Class.method string

Code, tested with 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'

Next step

If you want to check for the place of implementation in the code, you can do

>>> Uncle.test.__qualname__.split(".")[0] == Grandparent.__name__
True
>>> Child.test.__qualname__.split(".")[0] == Grandparent.__name__
False
>>> Child.test.__qualname__.split(".")[0] == Parent.__name__
True

Here it is demonstrated for a class instead of an instance.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文