4

Please check the simple code below:

def extract_class_from_func(func_var):
    # should return class of the func_var
    return ...

class A:
     def m(self):
         print(self, "m")

func_var = A.m

# This check should succeed
assert A == extract_class_from_func(func_var)

Please help me in implementing method extract_class_from_func

3 Answers 3

4

You can't. In Python 2, this reference was available at A.m.im_class. But, to quote from PEP 3155 - Qualified name for classes and functions:

This possibility is gone in Python 3.

There is no longer any such thing as an "unbound method" and the function A.m is no different from a regular function - it does not hold any reference to the class object. In fact, you can even delete the class and see the "method" still works:

>>> class Ameta(type):
...     def __del__(self):
...         print("goodbye A")
... 
>>> class A(metaclass=Ameta):
...     def m(self):
...         print(self, "m")
... 
>>> f = A.m
>>> import gc
>>> del A
>>> gc.collect()
goodbye A
6
>>> f("👻")
👻 m

However, the PEP did provide some limited support for what you wanted: if you look in A.m.__qualname__ you will find a string from which you may be able to introspect the class A.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for your answer. I learned something new about class methods :)
3

The module can be found using func_var.__module__ and class name can be found using __qualname__. Then you just perform string import as below:

import importlib    
def extract_class_from_func(func_var):
        className = func_var.__qualname__.split('.')[0]
        return getattr(importlib.import_module(func_var.__module__), className)



class Greet:
    def __init__(self):
        pass
    def sayHi(self):
        print("Hi!")


>>> Greet == extract_class_from_func(Greet.sayHi)
>>> True

3 Comments

This is a reasonable attempt at the introspection but maybe worth mentioning that it is not going to be reliable in some cases (nested classes, dynamically generated code, class name may have been rebound, __qualname__ has been overridden, etc..)
Yes, a little attention is needed. Here's the documentation on qualname if OP wants to handle more complicated cases.
Just changing __name__ to func_var.__module__ so that your solution can work even if func_var comes from some other module
0

You can do like this.

def extract_class_from_func(func_var):
    return func_var.__qualname__.split('.')[0]

1 Comment

This doesn't give you the class. It just gives you the string "A". So, the assertion shown in the question is still gonna fire.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.