177

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
Joan Venge
  • 315,713
  • 212
  • 479
  • 689

5 Answers5

269

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.

Ma0
  • 15,057
  • 4
  • 35
  • 65
Ayman Hourieh
  • 132,184
  • 23
  • 144
  • 116
  • 15
    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 – timeyyy Mar 23 '16 at 18:53
  • 6
    Actually, you probably want `inspect.currentframe().f_back.f_code.co_name`, which is independent of Python version or implementation. – 1313e May 29 '19 at 07:45
  • @1313e: also `inspect.currentframe()` depends from Python implementation, since if you read the source code of `inspect.py`, they both use `sys._getframe()` – Marco Sulla Oct 22 '19 at 21:08
  • thanks. also discovered that.filename can also help when .function alone is ambiguous. for example: `print(inspect.stack()[1].function, inspect.stack()[1].filename)` – 10mjg Feb 22 '20 at 22:00
  • Can it also print the full path of the function ? – alper Dec 11 '20 at 11:16
  • Is there an alternative method to get the same information from inside a class' `__init__`? – t3chb0t Apr 07 '23 at 12:13
38

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)
Eric
  • 1,138
  • 11
  • 24
  • 1
    Is this sys._getframe(1).f_code.co_name comparitively faster than inspect.stack()[1][3]? – jeffry copps Aug 20 '18 at 06:04
  • 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. – Eric Aug 21 '18 at 07:16
  • I wanted to know why because I knew it is faster. And I don't appreciate "seem" answers. – jeffry copps Aug 21 '18 at 08:50
  • 6
    (getframe) 0.00419473648071 : (inspect) 29.3846197128 Here is the ratio between the two for 4000 calls. – jeffry copps Aug 21 '18 at 08:51
  • 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. – Eric Aug 22 '18 at 17:28
16

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.

Piotr Findeisen
  • 19,480
  • 2
  • 52
  • 82
  • 14
    [sys._getframe](http://docs.python.org/library/sys.html#sys._getframe) is "not guaranteed to exist in all implementations of Python" - I think this is important to note. – RWS Sep 24 '11 at 20:36
9

This works for me! :D

>>> def a():
...     import sys
...     print sys._getframe(1).f_code.co_name
...
>>> def b():
...     a()
...
...
>>> b()
b
>>>
Alex Cory
  • 10,635
  • 10
  • 52
  • 62
  • This works great but at first it was confusing because you could have just had b() function echo it's own name. The other answers saying to use `inspect.` failed miserably because it wasn't defined. The authors forgot a dependency statement I guess. – WinEunuuchs2Unix Sep 08 '20 at 22:56
  • At least for me, this was **much** faster than `inspect.stack()` by at least a x1000 – Conchylicultor Feb 15 '22 at 14:31
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')
djvg
  • 11,722
  • 5
  • 72
  • 103
mescalin
  • 399
  • 5
  • 3
  • 1
    You inadvertently say `%(filename)s option`. It should be what you have in your code example: `%(funcName)s` :) – ᴠɪɴᴄᴇɴᴛ Aug 08 '14 at 12:44
  • 1
    It looks like `logging` uses the `sys._getframe()` approach under the hood, as can be seen [here](https://github.com/python/cpython/blob/48e352a2410b6e962d40359939a0d43aaba5ece9/Lib/logging/__init__.py#L169) and [here](https://github.com/python/cpython/blob/48e352a2410b6e962d40359939a0d43aaba5ece9/Lib/logging/__init__.py#L1611). – djvg Dec 15 '22 at 10:35