Get class that defined method
Solution 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
Solution 2
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__
.
Solution 3
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.
Solution 4
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
Solution 5
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
Related videos on Youtube
Comments
-
Jesse Aldridge almost 2 years
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)
-
Kathy Van Stone about 15 yearsWhat version of Python are you using? Before 2.2 you could use im_class, but that was changed to show the type of the bound self object.
-
Jesse Aldridge about 15 yearsGood to know. But I'm using 2.6.
-
-
Silas Ray over 11 years
Cls().meth.__self__
just gives you the instance ofCls
that is bound to that specific instance ofmeth
. It's analogous toCls().meth.im_class
. If you haveclass SCls(Cls)
,SCls().meth.__self__
will get you aSCls
instance, not aCls
instance. What the OP wants is to getCls
, which it appears is only available by walking the MRO as @Alex Martelli does. -
estani over 11 years@sr2222 You are right. I've modified the answer as I have already started though I think Alex solution is more compact.
-
Silas Ray over 11 yearsIt's a good solution if you need to avoid imports, but since you are basically just re-implementing the MRO, it's not guaranteed to work forever. The MRO will probably stay the same, but it was already changed once in Python's past, and if it is changed again, this code will result is subtle, pervasive bugs.
-
Codie CodeMonkey over 11 yearsBeware, not all classes implement
__dict__
! Sometimes__slots__
is used. It's probably better to usegetattr
to test if the method is in the class. -
sdupton over 11 years@DeepYellow: _slots_ are likely not relevant to a method defined on a class, as they describe storage in memory on instances of that class. The methods directly implemented on a class should always be in its _dict_.
-
Yoel almost 10 yearsFor
Python 3
, please refer to this answer. -
Zitrax about 9 yearsI am getting:
'function' object has no attribute 'im_class'
-
Alex Martelli almost 9 years@Zitrax, it works in Python 2 -- for Python 3, follow the link in Yoel's comment just before yours.
-
RedX about 8 yearsIn Python 2.7 it does not work. Same error about missing 'im_class'.
-
Dennis Golomazov over 6 yearsIf
meth
is aclassmethod
, replaceim_class
withim_self
. Works in Python 2.7.14. @AlexMartelli you might want to add it to the answer. -
Marc over 6 yearsfor those of use who are python 3 only -- is there anything wrong with using
meth.__qualname__
? -
F1Rumors almost 6 yearsHmm. I am not seeing the defining class when I do that in python 2.7 -- I am getting the class that the method was called on, not the one where it is defined...
-
ulidtko about 4 yearsTime and time again, "very unlikely scenarios" do happen in programming. Seldomly, causing disasters. In general, the thinking pattern "XY.Z% it won't ever happen" is extremely lousy thinking tool when doing coding. Don't use it. Write 100% correct code.
-
estani about 4 years@ulidtko I think you misread the explanation. It's not about correctness but speed. There is no "perfect" solution that fits all cases, otherwise e.g. there will be only one sorting algorithm. The solution proposed here should be faster in the "rare" case. Since speed comes in 99% percentage of all cases after readability, this solution might be a better solution in "only" that rare case. The code, in case you didn't read it, is 100% correct, if that was what you've feared.
-
Anakhand over 3 yearsWarning,
im_class
is a Python 2 only attribute so this won't work with unbound methods in Python 3 (which are just regular functions). -
FMc about 3 yearsThis can also be simplified to
bar.foo_method.__qualname__
to get'FooClass.foo_method
. I don't know whether there are edge cases for that approach, but it does work for the question at hand. -
ncaadam almost 3 yearsall the overly complex answers out there and this worked amazingly in python 3 - good work