198

If you have 2 functions like:

def A
def B

and A calls B, can you get who is calling B inside B, like:

def A () :
    B ()

def B () :
    this.caller.name
4
  • 1
    You have the source available. Why would you need such a thing? Commented May 23, 2009 at 1:36
  • 43
    Because I am debugging the code in a 3rd party app's python interpreter where there is no real debugger. Commented May 25, 2009 at 17:31
  • Related: How to log source file name and line number in Python. Commented Sep 24, 2018 at 22:35
  • 1
    Marking this as the duplicate since the other has more views and upvotes on the question. Commented Aug 30, 2019 at 14:35

5 Answers 5

294

You can use the inspect module to get the info you want. Its stack method returns a list of frame records.

  • For Python 2 each frame record is a list. The third element in each record is the caller name. What you want is this:

    >>> import inspect
    >>> def f():
    ...     print inspect.stack()[1][3]
    ...
    >>> def g():
    ...     f()
    ...
    >>> g()
    g
    

  • For Python 3.5+, each frame record is a named tuple so you need to replace

    print inspect.stack()[1][3]
    

    with

    print(inspect.stack()[1].function)
    

    on the above code.

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

6 Comments

on python 3.4 at least this doesn't work, they have changed the order of the tuples. A named tuple is now being used so it's best to use inspect.stack()[1].filename
Actually, you probably want inspect.currentframe().f_back.f_code.co_name, which is independent of Python version or implementation.
@1313e: also inspect.currentframe() depends from Python implementation, since if you read the source code of inspect.py, they both use sys._getframe()
thanks. also discovered that.filename can also help when .function alone is ambiguous. for example: print(inspect.stack()[1].function, inspect.stack()[1].filename)
Can it also print the full path of the function ?
|
39

There are two ways, using sys and inspect modules:

  • sys._getframe(1).f_code.co_name
  • inspect.stack()[1][3]

The stack() form is less readable and is implementation dependent since it calls sys._getframe(), see extract from inspect.py:

def stack(context=1):
    """Return a list of records for the stack above the caller's frame."""
    return getouterframes(sys._getframe(1), context)

5 Comments

Is this sys._getframe(1).f_code.co_name comparitively faster than inspect.stack()[1][3]?
Before rushing to ask, did you try to time it (using timeit for instance)? I think it's faster because it doesn't seem to incurr function calls and two list lookups. But things can get hidden in Python so the best is to timeit it. Let us know what you find.
I wanted to know why because I knew it is faster. And I don't appreciate "seem" answers.
(getframe) 0.00419473648071 : (inspect) 29.3846197128 Here is the ratio between the two for 4000 calls.
Great finding! I presume it's using CPython and Python version 2 or 3 doesn't affect much the result. Thanks for running the benchmark.
17

Note (June 2018): today, I would probably use inspect module, see other answers

sys._getframe(1).f_code.co_name like in the example below:

>>> def foo():
...  global x
...  x = sys._getframe(1)
...
>>> def y(): foo()
...
>>> y()
>>> x.f_code.co_name
'y'
>>>  

Important note: as it's obvious from the _getframe method name (hey, it starts with an underscore), it's not an API method one should be thoughtlessly rely on.

2 Comments

sys._getframe is "not guaranteed to exist in all implementations of Python" - I think this is important to note.
As of python 3.11 and forward, I would go directly with .f_code.co_qualname, as it provides the fully qualified function name, including the class. See here.
9

This works for me! :D

>>> def a():
...     import sys
...     print sys._getframe(1).f_code.co_name
...
>>> def b():
...     a()
...
...
>>> b()
b
>>>

1 Comment

At least for me, this was much faster than inspect.stack() by at least a x1000
6

you can user the logging module and specify the %(funcName)s option in BaseConfig()

import logging
logging.basicConfig(
    filename='/tmp/test.log', 
    level=logging.DEBUG, 
    format='%(asctime)s | %(levelname)s | %(funcName)s |%(message)s',
)

def A():
    logging.info('info')

2 Comments

You inadvertently say %(filename)s option. It should be what you have in your code example: %(funcName)s :)
It looks like logging uses the sys._getframe() approach under the hood, as can be seen here and here.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.