300

Python: How to get the caller's method name in the called method?

Assume I have 2 methods:

def method1(self): ... a = A.method2() def method2(self): ... 

If I don't want to do any change for method1, how to get the name of the caller (in this example, the name is method1) in method2?

1

14 Answers 14

352

inspect.getframeinfo and other related functions in inspect can help:

>>> import inspect >>> def f1(): f2() ... >>> def f2(): ... curframe = inspect.currentframe() ... calframe = inspect.getouterframes(curframe, 2) ... print('caller name:', calframe[1][3]) ... >>> f1() caller name: f1 

this introspection is intended to help debugging and development; it's not advisable to rely on it for production-functionality purposes.

Sign up to request clarification or add additional context in comments.

9 Comments

"it's not advisable to rely on it for production-functionality purposes." Why not?
@beltsonata it's dependent on the CPython implementation, so code using this will break if you ever try to use PyPy or Jython or other runtimes. that's fine if you're just developing and debugging locally but not really something you want in your production system.
@EugeneKrevenets Beyond just the python version, i just ran into an issue with it where it makes code that runs under a second run in multiple minutes once introduced. it grossly inefficient
Why this is not mentioned in the python3 documentation? docs.python.org/3/library/inspect.html They would at least put a warning if it is bad right?
Its a shame that this is such a hit on performance. Logging could be so much nicer with something like this (or CallerMemberName).
|
132

Shorter version:

import inspect def f1(): f2() def f2(): print ('caller name:', inspect.stack()[1][3]) f1() 

(with thanks to @Alex, and Stefaan Lippen)

3 Comments

Hello, I am getting below error when i run this: File "/usr/lib/python2.7/inspect.py", line 528, in findsource if not sourcefile and file[0] + file[-1] != '<>': IndexError: string index out of range Can u please provide suggestion. Thanx in advance.
This approach gave me an error: KeyError: 'main'
In Python 3 you need: print('caller name:', inspect.stack()[1][3])
92

This seems to work just fine:

import sys print sys._getframe().f_back.f_code.co_name 

7 Comments

This seems to be much faster than inspect.stack
Still it uses a protected member, which is generally not advised, because it could fail after the sys module gets some heavy refactoring.
Valid point. Thanks for putting it up here as a potential long term pitfall of this solution.
Also works with pyinstaller. Short & sweet. I use it with co_filename (instead of co_name) to know from which main program it is called or to know if it's called directly for testing purpose.
It is not protected member, it is documented in docs.python.org/3/library/sys.html#sys._getframe . It has underscore because it is implementation specific (Maybe CPython only). Anyway it is used by inspect module as well to get the stack.
|
66

I would use inspect.currentframe().f_back.f_code.co_name. Its use hasn't been covered in any of the prior answers which are mainly of one of three types:

  • Some prior answers use inspect.stack but it's known to be too slow.
  • Some prior answers use sys._getframe which is an internal private function given its leading underscore, and so its use is implicitly discouraged.
  • One prior answer uses inspect.getouterframes(inspect.currentframe(), 2)[1][3] but it's entirely unclear what [1][3] is accessing.
import inspect from types import FrameType from typing import cast def demo_the_caller_name() -> str: """Return the calling function's name.""" # Ref: https://stackoverflow.com/a/57712700/ return cast(FrameType, cast(FrameType, inspect.currentframe()).f_back).f_code.co_name if __name__ == '__main__': def _test_caller_name() -> None: assert demo_the_caller_name() == '_test_caller_name' _test_caller_name() 

Note that cast(FrameType, frame) is used to satisfy mypy.


Acknowlegement: comment by 1313e for an answer.

6 Comments

I was wondering what the caller name is if the function is called directly. Printing it results in <module>. Will this always be the case whenever the function is directly called by name? Or are there cases where the module name will pop-up?
@VahagnTumanyan If you call it from a module (from outside any function), it will say what you saw. This answer will not however show the module name. You can call it from a function to see the calling function's name.
It is the best way I guess, since there is no magic numbers like calframe[1][3] that can change in future.
Very nice, one more thing that's nice about this is it works in both Python 2 and 3 (or at least 2.7.18 and 3.9.7).
For those interested: inspect.currentframe() simply returns sys._getframe(1) or None. Also note that sys._getframe() is documented, but is considered an implementation detail.
|
38

I've come up with a slightly longer version that tries to build a full method name including module and class.

https://gist.github.com/2151727 (rev 9cccbf)

# Public Domain, i.e. feel free to copy/paste # Considered a hack in Python 2 import inspect def caller_name(skip=2): """Get a name of a caller in the format module.class.method `skip` specifies how many levels of stack to skip while getting caller name. skip=1 means "who calls me", skip=2 "who calls my caller" etc. An empty string is returned if skipped levels exceed stack height """ stack = inspect.stack() start = 0 + skip if len(stack) < start + 1: return '' parentframe = stack[start][0] name = [] module = inspect.getmodule(parentframe) # `modname` can be None when frame is executed directly in console # TODO(techtonik): consider using __main__ if module: name.append(module.__name__) # detect classname if 'self' in parentframe.f_locals: # I don't know any way to detect call from the object method # XXX: there seems to be no way to detect static method call - it will # be just a function call name.append(parentframe.f_locals['self'].__class__.__name__) codename = parentframe.f_code.co_name if codename != '<module>': # top level usually name.append( codename ) # function or a method ## Avoid circular refs and frame leaks # https://docs.python.org/2.7/library/inspect.html#the-interpreter-stack del parentframe, stack return ".".join(name) 

6 Comments

Awesome, this worked well for me in my logging code, where I can be called from a lot of different places. Thanks very much.
Unless you delete also stack, it still leaks frames due to cirular refs as explained in the inspect-docs
@ankostis do you have some test code to prove that?
Difficult to show in a comment... Copy-paste in an editor this driving code (typing from memory) and try both versions of your code: ``` import weakref class C: pass def kill(): print('Killed') def leaking(): caller_name() local_var = C() weakref.finalize(local_var, kill) leaking() print("Local_var must have been killed") ``` You should get: ``` Killed Local_var must have been killed ``` and not: ``` Local_var must have been killed Killed ```
Awesome! That worked when other solutions failed! I am using class methods and lambda-expressions so it's tricky.
|
14

Bit of an amalgamation of the stuff above. But here's my crack at it.

def print_caller_name(stack_size=3): def wrapper(fn): def inner(*args, **kwargs): import inspect stack = inspect.stack() modules = [(index, inspect.getmodule(stack[index][0])) for index in reversed(range(1, stack_size))] module_name_lengths = [len(module.__name__) for _, module in modules] s = '{index:>5} : {module:^%i} : {name}' % (max(module_name_lengths) + 4) callers = ['', s.format(index='level', module='module', name='name'), '-' * 50] for index, module in modules: callers.append(s.format(index=index, module=module.__name__, name=stack[index][3])) callers.append(s.format(index=0, module=fn.__module__, name=fn.__name__)) callers.append('') print('\n'.join(callers)) fn(*args, **kwargs) return inner return wrapper 

Use:

@print_caller_name(4) def foo(): return 'foobar' def bar(): return foo() def baz(): return bar() def fizz(): return baz() fizz() 

output is

level : module : name -------------------------------------------------- 3 : None : fizz 2 : None : baz 1 : None : bar 0 : __main__ : foo 

3 Comments

This will raise an IndexError if the requeted stack depth is greater than the actual. Use modules = [(index, inspect.getmodule(stack[index][0])) for index in reversed(range(1, min(stack_size, len(inspect.stack()))))] to get the modules.
Thanks a lot for that. I would suggest gathering modules a bit differently, aka: modules = [(index, module) for index in reversed(range(1, min(stack_size, len(stack)))) if index and (module := inspect.getmodule(stack[index][0]))]. That way you can ensure that you won't have Nones in your further lists. Also I think it's good to add module_name_lengths.append(len(func.__module__)), because the formatting doesn't take into account the element the lowest in the table.
In this solution, we should also probably return fn(*args, **kwargs), as the current solution suppresses returns from decorated functions and breaks them.
6

An alternative to sys._getframe() is used by Python's Logging library to find caller information. Here's the idea:

  1. raise an Exception

  2. immediately catch it in an Except clause

  3. use sys.exc_info to get Traceback frame (tb_frame).

  4. from tb_frame get last caller's frame using f_back.

  5. from last caller's frame get the code object that was being executed in that frame.

    In our sample code it would be method1 (not method2) being executed.

  6. From code object obtained, get the object's name -- this is caller method's name in our sample.

Here's the sample code to solve example in the question:

def method1(): method2() def method2(): try: raise Exception except Exception: frame = sys.exc_info()[2].tb_frame.f_back print("method2 invoked by: ", frame.f_code.co_name) # Invoking method1 method1() 

Output:

method2 invoked by: method1 

Frame has all sorts of details, including line number, file name, argument counts, argument type and so on. The solution works across classes and modules too.

1 Comment

This is much more suitable for a production-application. Thanks!
5

You can use decorators, and do not have to use stacktrace

If you want to decorate a method inside a class

import functools # outside ur class def printOuterFunctionName(func): @functools.wraps(func) def wrapper(self): print(f'Function Name is: {func.__name__}') func(self) return wrapper class A: @printOuterFunctionName def foo(): pass 

you may remove functools, self if it is procedural

1 Comment

Is this implementation more reliable compared to other suggestions?
4

Python has just made it better in 3.11, with the addition of codeobject.co_qualname, which return the function fully qualified name.

If you were using the solution from @Asclepius above, consider doing this instead, as it also includes the class name where the method is defined:

import inspect def who_is_calling(): print(inspect.currentframe().f_back.f_code.co_qualname) class Klass: def method(self): who_is_calling() # prints 'Klass.method' @classmethod def class_method(cls): who_is_calling() # prints 'Klass.class_method' @staticmethod def static_method(): who_is_calling() # prints 'Klass.static_method' who_is_calling() # prints 'Klass' class InnerKlass: def inner_method(self): who_is_calling() # prints 'Klass.InnerKlass.inner_method' def unbound_function(): who_is_calling() # prints 'unbound_function' 

What is good about this? It works for any functions, methods, class methods, static methods... and even a class itself (and nested classes)!

Comments

1

Code:

#!/usr/bin/env python import inspect called=lambda: inspect.stack()[1][3] def caller1(): print "inside: ",called() def caller2(): print "inside: ",called() if __name__=='__main__': caller1() caller2() 

Output:

shahid@shahid-VirtualBox:~/Documents$ python test_func.py inside: caller1 inside: caller2 shahid@shahid-VirtualBox:~/Documents$ 

1 Comment

called() is function that was called but not function that do call of callerN()
1

For multilevel calling with the purpose of only printing until before the module name, the following function is a simple solution:

import inspect def caller_name(): frames = inspect.stack() caller_name = '' for f in frames: if f.function == '<module>': return caller_name caller_name = f.function def a(): caller = caller_name() print(f"'a' was called from '{caller}'") def b(): a() def c(): b() c() 

Output:

'a' was called from 'c' 

Comments

0

I found a way if you're going across classes and want the class the method belongs to AND the method. It takes a bit of extraction work but it makes its point. This works in Python 2.7.13.

import inspect, os class ClassOne: def method1(self): classtwoObj.method2() class ClassTwo: def method2(self): curframe = inspect.currentframe() calframe = inspect.getouterframes(curframe, 4) print '\nI was called from', calframe[1][3], \ 'in', calframe[1][4][0][6: -2] # create objects to access class methods classoneObj = ClassOne() classtwoObj = ClassTwo() # start the program os.system('cls') classoneObj.method1() 

Comments

0

Here is a convenient method using @user47's answer.

def trace_caller(): try: raise Exception except Exception: frame = sys.exc_info()[2].tb_frame.f_back.f_back print(" >> invoked by:", frame.f_code.co_name) 

Comments

0

Here is how to get the calling method and its class:

import sys frame = sys._getframe().f_back calling_method = frame.f_code.co_name calling_class = frame.f_locals.get("self").__class__.__name__ 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.