I know how to get a caller method name (from here: How to get the caller's method name in the called method?)
import sys
print sys._getframe().f_back.f_code.co_name
What I'd like to get is the class name this method belongs to (assuming that it is in the class). So if:
def get_some_info():
print('Class name of caller:', XXX)
class Base:
def my_method(self):
get_some_info()
class A(Base):
pass
class B(Base):
pass
a = A()
b = B()
a.my_method()
b.my_method()
should return:
... A
... B
What should I do in xxx
?
I tried (using info on _getframe
) do something like:
sys._getframe().f_back.f_code.__self__
but it doesn't work
UPDATE:
I cannot pass class name to a called function (otherwise that would be easy, but thanks to all who suggested this solution!)
You can use StackFrame of System. Diagnostics and MethodBase of System. Reflection . StackFrame(Int32, Boolean) initializes a new instance of the StackFrame class that corresponds to a frame above the current stack frame, optionally capturing source information.
Method Class | getName() Method in JavaMethod class is helpful to get the name of methods, as a String. To get name of all methods of a class, get all the methods of that class object. Then call getName() on those method objects. Syntax: public String getName()
Method CallsA method is a routine that applies to a particular class of objects. Once an object is declared, you can refer to it by its identifier when calling methods. You can call methods for a window that has not previously been declared using a special identifier for dynamic instantiation.
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"
You could use inspect.stack()
:
def get_some_info():
_stack = inspect.stack()[1]
print ('cls:', _stack[0].f_locals['self'].__class__.__name__, 'func:', _stack[3])
....
a = A()
b = B()
a.my_method()
b.my_method()
Prints:
('cls:', 'A', 'func:', 'my_method')
('cls:', 'B', 'func:', 'my_method')
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With