问题
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?
回答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.
回答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
回答3:
There are a few ways to get the same result:
from __future__ import print_function
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
回答4:
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.
回答5:
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.
回答6:
I keep this handy utility nearby:
import inspect
myself = lambda: inspect.stack()[1][3]
Usage:
myself()
回答7:
I guess inspect is the best way to do this. For example:
import inspect
def bar():
print("My name is", inspect.stack()[0][3])
回答8:
I found a wrapper that will write the function name
from functools import wraps
def tmp_wrap(func):
@wraps(func)
def tmp(*args, **kwargs):
print func.__name__
return func(*args, **kwargs)
return tmp
@tmp_wrap
def my_funky_name():
print "STUB"
my_funky_name()
This will print
my_funky_name
STUB
回答9:
This is actually derived from the other answers to the question.
Here's my take:
import sys
# for current func name, specify 0 or no argument.
# for name of caller of current func, specify 1.
# for name of caller of caller of current func, specify 2. etc.
currentFuncName = lambda n=0: sys._getframe(n + 1).f_code.co_name
def testFunction():
print "You are in function:", currentFuncName()
print "This function's caller was:", currentFuncName(1)
def invokeTest():
testFunction()
invokeTest()
# end of file
The likely advantage of this version over using inspect.stack() is that it should be thousands of times faster [see Alex Melihoff's post and timings regarding using sys._getframe() versus using inspect.stack() ].
回答10:
print(inspect.stack()[0].function) seems to work too (Python 3.5).
回答11:
Here's a future-proof approach.
Combining @CamHart's and @Yuval's suggestions with @RoshOxymoron's accepted answer has the benefit of avoiding:
_hiddenand potentially deprecated methods- indexing into the stack (which could be reordered in future pythons)
So I think this plays nice with future python versions (tested on 2.7.3 and 3.3.2):
from __future__ import print_function
import inspect
def bar():
print("my name is '{}'".format(inspect.currentframe().f_code.co_name))
回答12:
import inspect
def whoami():
return inspect.stack()[1][3]
def whosdaddy():
return inspect.stack()[2][3]
def foo():
print "hello, I'm %s, daddy is %s" % (whoami(), whosdaddy())
bar()
def bar():
print "hello, I'm %s, daddy is %s" % (whoami(), whosdaddy())
foo()
bar()
In IDE the code outputs
hello, I'm foo, daddy is
hello, I'm bar, daddy is foo
hello, I'm bar, daddy is
回答13:
import sys
def func_name():
"""
:return: name of caller
"""
return sys._getframe(1).f_code.co_name
class A(object):
def __init__(self):
pass
def test_class_func_name(self):
print(func_name())
def test_func_name():
print(func_name())
Test:
a = A()
a.test_class_func_name()
test_func_name()
Output:
test_class_func_name
test_func_name
回答14:
You can use a decorator:
def my_function(name=None):
return name
def get_function_name(function):
return function(name=function.__name__)
>>> get_function_name(my_function)
'my_function'
回答15:
I am not sure why people make it complicated:
import sys
print("%s/%s" %(sys._getframe().f_code.co_filename, sys._getframe().f_code.co_name))
回答16:
I did what CamHart said:
import sys
def myFunctionsHere():
print(sys._getframe().f_code.co_name)
myFunctionsHere()
Output:
C:\Python\Python36\python.exe C:/Python/GetFunctionsNames/TestFunctionsNames.py myFunctionsHere
Process finished with exit code 0
回答17:
I do my own approach used for calling super with safety inside multiple inheritance scenario (I put all the code)
def safe_super(_class, _inst):
"""safe super call"""
try:
return getattr(super(_class, _inst), _inst.__fname__)
except:
return (lambda *x,**kx: None)
def with_name(function):
def wrap(self, *args, **kwargs):
self.__fname__ = function.__name__
return function(self, *args, **kwargs)
return wrap
sample usage:
class A(object):
def __init__():
super(A, self).__init__()
@with_name
def test(self):
print 'called from A\n'
safe_super(A, self)()
class B(object):
def __init__():
super(B, self).__init__()
@with_name
def test(self):
print 'called from B\n'
safe_super(B, self)()
class C(A, B):
def __init__():
super(C, self).__init__()
@with_name
def test(self):
print 'called from C\n'
safe_super(C, self)()
testing it :
a = C()
a.test()
output:
called from C
called from A
called from B
Inside each @with_name decorated method you have access to self.__fname__ as the current function name.
回答18:
Use this (based on #Ron Davis's answer):
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
回答19:
I recently tried to use the above answers to access the docstring of a function from the context of that function but as the above questions were only returning the name string it did not work.
Fortunately I found a simple solution. If like me, you want to refer to the function rather than simply get the string representing the name you can apply eval() to the string of the function name.
import sys
def foo():
"""foo docstring"""
print(eval(sys._getframe().f_code.co_name).__doc__)
回答20:
I suggest not to rely on stack elements. If someone use your code within different contexts (python interpreter for instance) your stack will change and break your index ([0][3]).
I suggest you something like that:
class MyClass:
def __init__(self):
self.function_name = None
def _Handler(self, **kwargs):
print('Calling function {} with parameters {}'.format(self.function_name, kwargs))
self.function_name = None
def __getattr__(self, attr):
self.function_name = attr
return self._Handler
mc = MyClass()
mc.test(FirstParam='my', SecondParam='test')
mc.foobar(OtherParam='foobar')
来源:https://stackoverflow.com/questions/5067604/determine-function-name-from-within-that-function-without-using-traceback