Get class that defined method
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
Find class in which a method is defined
If you need this in Python 3.x, please see my other answer—the closure cell __class__
is all you need.
If you need to do this in CPython 2.6-2.7, RickyA's answer is close, but it doesn't work, because it relies on the fact that this method is not overriding any other method of the same name. Try adding a Foo.do_it
method in his answer, and it will print out Foo
, not SomeClass
The way to solve that is to find the method whose code object is identical to the current frame's code object:
def do_it(self):
mro = inspect.getmro(self.__class__)
method_code = inspect.currentframe().f_code
method_name = method_code.co_name
for base in reversed(mro):
try:
if getattr(base, method_name).func_code is method_code:
print(base.__name__)
break
except AttributeError:
pass
(Note that the AttributeError
could be raised either by base
not having something named do_it
, or by base
having something named do_it
that isn't a function, and therefore doesn't have a func_code
. But we don't care which; either way, base
is not the match we're looking for.)
This may work in other Python 2.6+ implementations. Python does not require frame objects to exist, and if they don't, inspect.currentframe()
will return None
. And I'm pretty sure it doesn't require code objects to exist either, which means func_code
could be None
.
Meanwhile, if you want to use this in both 2.7+ and 3.0+, change that func_code
to __code__
, but that will break compatibility with earlier 2.x.
If you need CPython 2.5 or earlier, you can just replace the inpsect
calls with the implementation-specific CPython attributes:
def do_it(self):
mro = self.__class__.mro()
method_code = sys._getframe().f_code
method_name = method_code.co_name
for base in reversed(mro):
try:
if getattr(base, method_name).func_code is method_code:
print(base.__name__)
break
except AttributeError:
pass
Note that this use of mro()
will not work on classic classes; if you really want to handle those (which you really shouldn't want to…), you'll have to write your own mro
function that just walks the hierarchy old-school… or just copy it from the 2.6 inspect
source.
This will only work in Python 2.x implementations that bend over backward to be CPython-compatible… but that includes at least PyPy. inspect
should be more portable, but then if an implementation is going to define frame
and code
objects with the same attributes as CPython's so it can support all of inspect
, there's not much good reason not to make them attributes and provide sys._getframe
in the first place…
How do I get list of methods in a Python class?
An example (listing the methods of the optparse.OptionParser
class):
>>> from optparse import OptionParser
>>> import inspect
#python2
>>> inspect.getmembers(OptionParser, predicate=inspect.ismethod)
[([('__init__', <unbound method OptionParser.__init__>),
...
('add_option', <unbound method OptionParser.add_option>),
('add_option_group', <unbound method OptionParser.add_option_group>),
('add_options', <unbound method OptionParser.add_options>),
('check_values', <unbound method OptionParser.check_values>),
('destroy', <unbound method OptionParser.destroy>),
('disable_interspersed_args',
<unbound method OptionParser.disable_interspersed_args>),
('enable_interspersed_args',
<unbound method OptionParser.enable_interspersed_args>),
('error', <unbound method OptionParser.error>),
('exit', <unbound method OptionParser.exit>),
('expand_prog_name', <unbound method OptionParser.expand_prog_name>),
...
]
# python3
>>> inspect.getmembers(OptionParser, predicate=inspect.isfunction)
...
Notice that getmembers
returns a list of 2-tuples. The first item is the name of the member, the second item is the value.
You can also pass an instance to getmembers
:
>>> parser = OptionParser()
>>> inspect.getmembers(parser, predicate=inspect.ismethod)
...
get a class name of calling method
You can get the calling frame object with inspect.currentframe()
and get the object that self
is bound to through its f_locals
attribute:
import inspect
def get_some_info():
# get the call frame of the calling method
frame = inspect.currentframe().f_back
try:
# try to access the caller's "self"
try:
self_obj = frame.f_locals['self']
except KeyError:
return None
# get the class of the "self" and return its name
return type(self_obj).__name__
finally:
# make sure to clean up the frame at the end to avoid ref cycles
del frame
The disadvantage of this is that it relies on the first parameter to be named "self". There are a few cases where we use different names, for example when writing a metaclass:
class MyMeta(type):
def __call__(cls, *args, **kwargs):
get_some_info() # won't work!
And if you have a function with a self
variable, it can produce unexpected results:
def not_a_method():
self = 3
print(get_some_info()) # output: int
We can solve both of these problems, but it takes a lot of work. We can inspect the name of the "self" parameter through the calling code object's co_varnames
attribute. And in order to check whether the calling function is really a method defined in a class, we can loop through the self
's MRO and try to find the method that called us. The end result is this monstrosity:
def get_some_info():
# get the call frame of the calling method
frame = inspect.currentframe().f_back
try:
# find the name of the first variable in the calling
# function - which is hopefully the "self"
codeobj = frame.f_code
try:
self_name = codeobj.co_varnames[0]
except IndexError:
return None
# try to access the caller's "self"
try:
self_obj = frame.f_locals[self_name]
except KeyError:
return None
# check if the calling function is really a method
self_type = type(self_obj)
func_name = codeobj.co_name
# iterate through all classes in the MRO
for cls in self_type.__mro__:
# see if this class has a method with the name
# we're looking for
try:
method = vars(cls)[func_name]
except KeyError:
continue
# unwrap the method just in case there are any decorators
try:
method = inspect.unwrap(method)
except ValueError:
pass
# see if this is the method that called us
if getattr(method, '__code__', None) is codeobj:
return self_type.__name__
# if we didn't find a matching method, return None
return None
finally:
# make sure to clean up the frame at the end to avoid ref cycles
del frame
This should handle pretty much everything you throw at it correctly:
class Base:
def my_method(whatever):
print(get_some_info())
@functools.lru_cache() # could be any properly implemented decorator
def my_decorated_method(foo):
print(get_some_info())
@classmethod
def my_class_method(cls):
print(get_some_info())
class A(Base):
pass
def not_a_method(self=3):
print(get_some_info())
A().my_method() # prints "A"
A().my_decorated_method() # prints "A"
A.my_class_method() # prints "None"
not_a_method() # prints "None"
print(get_some_info()) # prints "None"
In Python, how can you get the name of a member function's class?
testFunc.im_class
https://docs.python.org/reference/datamodel.html#the-standard-type-hierarchy
im_class
is the class ofim_self
for
bound methods or the class that asked
for the method for unbound methods
how to get class name of a class static method through inspection
That is the very definition of a static method: it is called without a class argument (as in class methods) and without an instance argument (as in instance methods). The only real difference between a function declared in module scope and a static method is that the method name is defined in the class' namespace and not in the module's namespace.
In other words, you can't get to the class object directly. You can get the function name by examining the stack (although I am not sure how useful it is):
>>> import sys
>>> import traceback
>>> class A(object):
@staticmethod
def a():
trace()
>>> def trace():
print traceback.extract_stack(sys._getframe())[-3][3]
>>> A.a()
A.a()
And given the name, you could get to the class object by extracting from the name and looking it up in the module's namespace...
For reference:
frame @ -1 : call to traceback.extract_stack()
frame @ -2 : call to trace()
frame @ -3 : call to A.a()
checking if a method is defined on the class
Use this:
C.instance_methods(false).include?(:a)
C.instance_methods(false).include?(:b)
C.instance_methods(false).include?(:c)
The method instance_methods
return an Array of methods that an instance of this class would have. Passing false
as first parameter returns only methods of this class, not methods of super classes.
So C.instance_methods(false)
returns the list of methods defined by C
.
Then you just have to check if that method is in the returned Array (this is what the include?
calls do).
See docs
Related Topics
Stream Large Binary Files with Urllib2 to File
Handling Backreferences to Capturing Groups in Re.Sub Replacement Pattern
Dll Load Failed Error When Importing Cv2
Tkinter Adding Line Number to Text Widget
Reversing 'One-Hot' Encoding in Pandas
What Is the Cause of the Bad Request Error When Submitting Form in Flask Application
Subclassing Tuple with Multiple _Init_ Arguments
Module' Object Has No Attribute 'Loads' While Parsing JSON Using Python
How to Sort Python List of Strings of Numbers
How to Put Parameterized SQL Query into Variable and Then Execute in Python
Efficiently Convert Uneven List of Lists to Minimal Containing Array Padded with Nan
Moving Balls in Tkinter Canvas
How to Build a Recursive Function in Python
Building Python with Ssl Support in Non-Standard Location