问题
My objective is to stimulate a sequence diagram of an application for this I need the information about a caller and callee class names at runtime. I can successfully retrieve the caller function but not able to get a caller class name?
#Scenario caller.py:
import inspect
class A:
def Apple(self):
print "Hello"
b=B()
b.Bad()
class B:
def Bad(self):
print"dude"
print inspect.stack()
a=A()
a.Apple()
When I printed the stack there was no information about the caller class. So is it possible to retrieve the caller class during runtime ?
回答1:
Well, after some digging at the prompt, here's what I get:
stack = inspect.stack()
the_class = stack[1][0].f_locals["self"].__class__
the_method = stack[1][0].f_code.co_name
print("I was called by {}.{}()".format(str(calling_class), calling_code_name))
# => I was called by A.a()
When invoked:
➤ python test.py
A.a()
B.b()
I was called by __main__.A.a()
given the file test.py
:
import inspect
class A:
def a(self):
print("A.a()")
B().b()
class B:
def b(self):
print("B.b()")
stack = inspect.stack()
the_class = stack[1][0].f_locals["self"].__class__
the_method = stack[1][0].f_code.co_name
print(" I was called by {}.{}()".format(str(the_class), the_method))
A().a()
Not sure how it will behave when called from something other than an object.
回答2:
Using the answer from Python: How to retrieve class information from a 'frame' object?
I get something like this...
import inspect
def get_class_from_frame(fr):
args, _, _, value_dict = inspect.getargvalues(fr)
# we check the first parameter for the frame function is
# named 'self'
if len(args) and args[0] == 'self':
# in that case, 'self' will be referenced in value_dict
instance = value_dict.get('self', None)
if instance:
# return its class
return getattr(instance, '__class__', None)
# return None otherwise
return None
class A(object):
def Apple(self):
print "Hello"
b=B()
b.Bad()
class B(object):
def Bad(self):
print"dude"
frame = inspect.stack()[1][0]
print get_class_from_frame(frame)
a=A()
a.Apple()
which gives me the following output:
Hello
dude
<class '__main__.A'>
clearly this returns a reference to the class itself. If you want the name of the class, you can get that from the __name__
attribute.
Unfortunately, this won't work for class or static methods ...
回答3:
Perhaps this is breaking some Python programming protocol, but if Bad is always going to check the class of the caller, why not pass the caller's __class__
to it as part of the call?
class A:
def Apple(self):
print "Hello"
b=B()
b.Bad(self.__class__)
class B:
def Bad(self, cls):
print "dude"
print "Calling class:", cls
a=A()
a.Apple()
Result:
Hello
dude
Calling class: __main__.A
If this is bad form, and using inspect
truly is the preferred way to get the caller's class, please explain why. I'm still learning about deeper Python concepts.
回答4:
To store class instance name from the stack to class variable:
import inspect
class myClass():
caller = ""
def __init__(self):
s = str(inspect.stack()[1][4]).split()[0][2:]
self.caller = s
def getInstanceName(self):
return self.caller
This
myClassInstance1 = myClass()
print(myClassInstance1.getInstanceName())
will print:
myClassInstance1
回答5:
Instead of indexing the return value of inspect.stack(), one could use the method inspect.currentframe(), which avoids the indexing.
prev_frame = inspect.currentframe().f_back
the_class = prev_frame.f_locals["self"].__class__
the_method = prev_frame.f_code.co_name
来源:https://stackoverflow.com/questions/17065086/how-to-get-the-caller-class-name-inside-a-function-of-another-class-in-python