Given x = C.f
after:
class C:
def f(self):
pass
What do I call on x
that will return C
?<
If your aim is to get rid of the exec
statement, but are willing to use the __qualname__ attribute, even though you are still required to manually parse it, then at least for simple cases the following seems to work:
x.__globals__[x.__qualname__.rsplit('.', 1)[0]]
or:
getattr(inspect.getmodule(x), x.__qualname__.rsplit('.', 1)[0])
I'm not a Python
expert, but I think the second solution is better, considering the following documentation excerpts:
from What's new in Python 3.3:
Functions and class objects have a new
__qualname__
attribute representing the “path” from the module top-level to their definition. For global functions and classes, this is the same as__name__
. For other functions and classes, it provides better information about where they were actually defined, and how they might be accessible from the global scope.
from __qualname__'s description in PEP 3155:
For nested classed, methods, and nested functions, the
__qualname__
attribute contains a dotted path leading to the object from the module top-level.
EDIT:
As noted in the comments by @eryksun, parsing __qualname__
like this goes beyond its intended usage and is extremely fragile considering how __qualname__
reflects closures. A more robust approach needs to exclude closure namespaces of the form name.
. For example:
>>> class C:
... f = (lambda x: lambda s: x)(1)
...
>>> x = C.f
>>> x
.. at 0x7f13b58df730>
>>> x.__qualname__
'C...'
>>> getattr(inspect.getmodule(x), x.__qualname__.rsplit('.', 1)[0])
Traceback (most recent call last):
File "", line 1, in
AttributeError: 'module' object has no attribute 'C..'
This specific case can be handled in the following manner:
>>> getattr(inspect.getmodule(x),
... x.__qualname__.split('.', 1)[0].rsplit('.', 1)[0])
Nonetheless, it's unclear what other corner cases exist now or may come up in future releases.
As noted in the comment by @MichaelPetch, this answer is relevant only for Python 3.3
onward, as only then the __qualname__ attribute was introduced into the language.
Python
versions.For a complete solution that handles bound methods as well, please refer to this answer.