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 retrie
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.
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
Python 3.8
import inspect
class B:
def __init__(self):
if (parent := inspect.stack()[1][0].f_locals.get('self', None)) and isinstance(parent, A):
parent.print_coin()
class A:
def __init__(self, coin):
self.coin: str = coin
B()
def print_coin(self):
print(f'Coin name: {self.coin}')
A('Bitcoin')
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 ...
Well, after some digging at the prompt, here's what I get:
stack = inspect.stack()
the_class = stack[1][0].f_locals["self"].__class__.__name__
the_method = stack[1][0].f_code.co_name
print("I was called by {}.{}()".format(the_class, the_method))
# => I was called by A.a()
When invoked:
➤ python test.py
A.a()
B.b()
I was called by 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__.__name__
the_method = stack[1][0].f_code.co_name
print(" I was called by {}.{}()".format(the_class, the_method))
A().a()
Not sure how it will behave when called from something other than an object.
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