Determine function name from within that function (without using traceback)

362,429

Solution 1

Python doesn't have a feature to access the function or its name within the function itself. It has been proposed but rejected. If you don't want to play with the stack yourself, you should either use "bar" or bar.__name__ depending on context.

The given rejection notice is:

This PEP is rejected. It is not clear how it should be implemented or what the precise semantics should be in edge cases, and there aren't enough important use cases given. response has been lukewarm at best.

Solution 2

import inspect

def foo():
   print(inspect.stack()[0][3])
   print(inspect.stack()[1][3])  # will give the caller of foos name, if something called foo

foo()

output:

foo
<module_caller_of_foo>

Solution 3

There are few ways to get the same result:

import sys
import inspect

def what_is_my_name():
    print(inspect.stack()[0][0].f_code.co_name)
    print(inspect.stack()[0][3])
    print(inspect.currentframe().f_code.co_name)
    print(sys._getframe().f_code.co_name)

Note that the inspect.stack calls are thousands of times slower than the alternatives:

$ python -m timeit -s 'import inspect, sys' 'inspect.stack()[0][0].f_code.co_name'
1000 loops, best of 3: 499 usec per loop
$ python -m timeit -s 'import inspect, sys' 'inspect.stack()[0][3]'
1000 loops, best of 3: 497 usec per loop
$ python -m timeit -s 'import inspect, sys' 'inspect.currentframe().f_code.co_name'
10000000 loops, best of 3: 0.1 usec per loop
$ python -m timeit -s 'import inspect, sys' 'sys._getframe().f_code.co_name'
10000000 loops, best of 3: 0.135 usec per loop

Update 08/2021 (original post was written for Python2.7)

Python 3.9.1 (default, Dec 11 2020, 14:32:07)
[GCC 7.3.0] :: Anaconda, Inc. on linux

python -m timeit -s 'import inspect, sys' 'inspect.stack()[0][0].f_code.co_name'
500 loops, best of 5: 390 usec per loop
python -m timeit -s 'import inspect, sys' 'inspect.stack()[0][3]'
500 loops, best of 5: 398 usec per loop
python -m timeit -s 'import inspect, sys' 'inspect.currentframe().f_code.co_name'
2000000 loops, best of 5: 176 nsec per loop
python -m timeit -s 'import inspect, sys' 'sys._getframe().f_code.co_name'
5000000 loops, best of 5: 62.8 nsec per loop

Solution 4

functionNameAsString = sys._getframe().f_code.co_name

I wanted a very similar thing because I wanted to put the function name in a log string that went in a number of places in my code. Probably not the best way to do that, but here's a way to get the name of the current function.

Solution 5

You can get the name that it was defined with using the approach that @Andreas Jung shows, but that may not be the name that the function was called with:

import inspect

def Foo():
   print inspect.stack()[0][3]

Foo2 = Foo

>>> Foo()
Foo

>>> Foo2()
Foo

Whether that distinction is important to you or not I can't say.

Share:
362,429
Rob
Author by

Rob

Updated on April 27, 2022

Comments

  • Rob
    Rob about 2 years

    In Python, without using the traceback module, is there a way to determine a function's name from within that function?

    Say I have a module foo with a function bar. When executing foo.bar(), is there a way for bar to know bar's name? Or better yet, foo.bar's name?

    #foo.py  
    def bar():
        print "my name is", __myname__ # <== how do I calculate this at runtime?
    
    • sancho.s ReinstateMonicaCellio
      sancho.s ReinstateMonicaCellio over 7 years
      I do not understand why the accepted answer is not that from Andreas Young (or any other that shows how to do it). Instead, the accepted answer is "you can't do that", which seems wrong; the only requirement by the OP was not using traceback. Not even the times of answers and comments seem to back it.
    • Rotem Shalev
      Rotem Shalev about 3 years
      Hey @Rob, could you please elaborate on why you've picked the accepted answer as accepted? It seems like it's not currently relevant in this context, as other answers did work (for me) while the accepted one said this is impossible
    • DevPlayer
      DevPlayer about 3 years
      For the simplest unaccepted answer for Python 3.x + see Vagiz Duseev's answer below Answer.
  • Kos
    Kos over 11 years
    Same situation as with .func_name. Worth remembering that class names and function names in Python is one thing and variables referring to them is another.
  • Harvey
    Harvey about 11 years
    Sometimes you may want Foo2() to print Foo. For example: Foo2 = function_dict['Foo']; Foo2(). In this case, Foo2 is a function pointer for perhaps a command line parser.
  • Robert C. Barth
    Robert C. Barth over 10 years
    What kind of speed implication does this have?
  • Michael
    Michael over 10 years
    You could also use: print(inspect.currentframe().f_code.co_name) or to get the caller's name: print(inspect.currentframe().f_back.f_code.co_name). I think it should be faster since you don't retrieve a list of all the stack frames as inspect.stack() does.
  • bgporter
    bgporter over 10 years
    Speed implication with regard to what? Is there a situation where you'd need to have this information in a hard realtime situation or something?
  • Yuval
    Yuval almost 10 years
    inspect.currentframe() is one such way.
  • hobs
    hobs over 9 years
    Combining @CamHart's approach with @Yuval's avoids "hidden" and potentially deprecated methods in @RoshOxymoron's answer as well as numerical indexing into the stack for @neuro/@AndreasJung's answer: print(inspect.currentframe().f_code.co_name)
  • Dustin Wyatt
    Dustin Wyatt over 8 years
    inspect.currentframe().f_back.f_code.co_name doesn't work with a decorated method whereas inspect.stack()[0][3] does...
  • m3nda
    m3nda about 8 years
    Totally working, just using sys, don't need to load more modules, but not soo easy to remember it :V
  • FabienAndre
    FabienAndre almost 8 years
    inspect.currentframe() seems a good tradeoff between execution time and use of private members
  • gardarh
    gardarh over 7 years
    Please note: inspect.stack() can incur heavy performance overhead so use sparingly! On my arm box it took 240ms to complete (for some reason)
  • Antony Hatchkins
    Antony Hatchkins over 7 years
    @mbdevpl My numbers are 1.25ms, 1.24ms, 0.5us, 0.16us normal (nonpythonic :) ) seconds accordingly (win7x64, python3.5.1)
  • dwanderson
    dwanderson over 7 years
    Just so no one thinks@mbdevpl is crazy :) - I submitted an edit for the output of the 3rd run, since it didn't make any sense. No idea if the result should've been 0.100 usec or 0.199 usec but either way - hundreds of times faster than options 1 and 2, comparable with option 4 (though Antony Hatchkins found option 3 three times faster than option 4).
  • NYCeyes
    NYCeyes about 7 years
    How would this be done with the alternative proposed here? "myself = lambda: sys._getframe().f_code.co_name" doesn't work (the output is "<lambda>"; I think because the result is determined at definition time, not later at call time. Hmm.
  • Charlie Parker
    Charlie Parker about 7 years
    is it possible to summarize why its been rejected?
  • cowbert
    cowbert almost 7 years
    As a decorator noob, I wonder if there is a way to access func.__name__ inside the context of my_funky_name (so I can retrieve its value and use it inside my_funky_name)
  • cad106uk
    cad106uk almost 7 years
    The way to do that inside the my_funky_name function is my_funky_name.__name__. You could pass the func.__name__ into the function as a new parameter. func(*args, **kwargs, my_name=func.__name__). To get your decorators name from inside your function, I think that would require using inspect. But getting the name of the function controlling my function within my running function ... well that just sounds like the start of a beautiful meme :)
  • Tom Russell
    Tom Russell almost 7 years
    Seems to me like something present in the Python recursion machinery might be employed to do this more efficiently
  • ijw
    ijw over 6 years
    @prismalytics.io: If you call myself (myself()) and don't just use its value (myself), you'll get what you're looking for.
  • nerdfever.com
    nerdfever.com almost 6 years
    @erm3nda See my answer.
  • m3nda
    m3nda almost 6 years
    @nerdfever.com My problem is not about to create a function, is to not remember what to put inside that function. Is not easy to remember so i will need always to see some note to build that again. I'll try to keep in mind f for frame and co for code. I don't use that so much so the better if just i save that in some snippet :-)
  • parvus
    parvus over 5 years
    How is that answering the poster's question? Can you expand this to include an example how the function name is known from within the function?
  • Douglas Denhartog
    Douglas Denhartog over 5 years
    @parvus: my answer as is is an example that demonstrates an answer to OP's question
  • parvus
    parvus about 5 years
    Ok, my_function is the random user's function of the OP. Blame this to my lack of understanding of decorators. Where the @? How will this work for functions whose arguments you don't want to adapt? How I understand your solution: when I want to know the function name, I have to append it with @get_function_name, and add the name argument, hoping it is not already there for another purpose. I'm likely missing something, sorry for that.
  • Douglas Denhartog
    Douglas Denhartog about 5 years
    Without starting my own python course inside a comment: 1. functions are objects; 2. you could attach a name attribute to the function, print/log the name, or do any number of things with the "name" inside the decorator; 3. decorators can be attached multiple ways (e.g. @ or in my example); 4. decorators can use @wraps and/or be classes themselves; 5. I could go on, but, happy programming!
  • nurettin
    nurettin about 5 years
    why is this the chosen answer? Question isn't about accessing the current function or the module itself, just the name. And the stacktrace/debugging features already have this information.
  • Avi
    Avi about 5 years
    This just looks like a convoluted way to get to the __name__ attribute of a function. The usage requires knowing the thing you are trying to get, which doesn't seem very useful to me in simple cases where functions aren't defined on the fly.
  • kikones34
    kikones34 over 4 years
    NYCeyes was right, the name is resolved inside the lambda and thus the result is <lambda>. The sys._getframe() and inspect.currentframe() methods MUST be executed directly inside the function you want to get the name of. The inspect.stack() method works because you can specify the index 1, doing inspect.stack()[0][3] also yields <lambda>.
  • user2357112
    user2357112 over 4 years
    This gets the code object's name, not the function's name. Function names and code object names often diverge when using decorators, due to function __name__ reassignment. The code object's name will not reflect function __name__ changes.
  • tikej
    tikej about 4 years
    maybe because you're using private function of sys module, outside of it. In general it is considered a bad practice, ain't it?
  • karthik r
    karthik r about 4 years
    @tikej, the usage agrees to the best practice stated here: docs.quantifiedcode.com/python-anti-patterns/correctness/…
  • Давид Шико
    Давид Шико about 4 years
    @Michael please post your comment as an answer .
  • PatrickT
    PatrickT about 4 years
    I use sys._getframe().f_code.co_name over inspect.currentframe().f_code.co_name simply because I have already imported the sys module. Is that a reasonable decision? (considering the speeds appear quite similar)
  • Nam G VU
    Nam G VU almost 4 years
    This is fullblow answer and should be the accepted one in my view
  • Tom Pohl
    Tom Pohl over 3 years
    Instead if using inspect.stack()[0][3], use inspect.stack()[0].function which should be more robust even when semantics in stack traces change.
  • Greenonline
    Greenonline about 3 years
    @nerdfever.com - what answer? Have you deleted it?
  • nerdfever.com
    nerdfever.com about 3 years
    @m3nda My answer was "deleted" and is visible only to me (I have no idea why!) It's this: import sys def thisFunctionName(): """Returns a string with the name of the function it's called from""" return sys._getframe(1).f_code.co_name
  • nerdfever.com
    nerdfever.com about 3 years
    @Greenonline My answer was an elaboration of Ron Davis's answer, solving m3nda's problem, that was "deleted by moderator" and is visible only to me (I have no idea why! Maybe "plagiarism", but I credited Ron Davis's answer!) It's this: import sys def thisFunctionName(): """Returns a string with the name of the function it's called from""" return sys._getframe(1).f_code.co_name
  • Fernando Crespo
    Fernando Crespo about 3 years
    We can use sys._getframe().f_back.f_code.co_name to get the callers name too
  • DevPlayer
    DevPlayer about 3 years
    As of today, tested within my CPython 3.7.2 bar.__name__ does work. For the simplest unaccepted answer for Python 3.x + see Vagiz Duseev's answer below Answer.
  • TheEagle
    TheEagle about 3 years
    @hobs Combining @CamHart's approach with @Yuval's avoids "hidden" and potentially deprecated methods in @RoshOxymoron's answer as well as numerical indexing into the stack for @neuro/@AndreasJung's answer - hmm … However did you @notify so much guys at once ?
  • Florian
    Florian about 3 years
    This answer is too old. It is now wrong. Please delete it.
  • PyNoob
    PyNoob almost 3 years
    What would be the point of this if the function name "bar" would have to be known already to perform this?
  • Manifest Man
    Manifest Man almost 3 years
    sys._getframe().f_back.f_code.co_name does not work at all in python 3.9
  • MEMark
    MEMark almost 3 years
    What is the purpose of from __future__ import print_function? Works fine for me without it.
  • MEMark
    MEMark almost 3 years
    Except that the question is not about line numbers.
  • Manifest Man
    Manifest Man almost 3 years
    @MEMark i updated my answer accordently, you should have noticed the textual error, but i have also investigate the issue, and i came to the conclusion, that the call sys._getframe().f_back.f_code.co_name works allthough the IDE PyCharm does not recognize it Cannot find reference '_getframe' in 'sys.pyi | sys.pyi'. That,s why i wrote that answer before.
  • Manifest Man
    Manifest Man almost 3 years
    @MEMark here is the post, i wrote on this issue : https://stackoverflow.com/q/68772415/5667103
  • Alex  Granovsky
    Alex Granovsky almost 3 years
    @MEMark this is legacy ;-)
  • Abdelsalam Hamdi
    Abdelsalam Hamdi almost 3 years
    using inspect is very slow like the answer suggested, I think everyone really needs to consider this.
  • Gerhard
    Gerhard over 2 years
    @PyNoob: After renaming bar to foo, print('bar') happily prints (incorrectly) "bar", whereas print(bar.__name__) fails.
  • Sinux1
    Sinux1 over 2 years
    Works in python 3.7