在Python中,如果不使用
假设我有一个带函数栏的foo模块。执行
1 2 3 | #foo.py def bar(): print"my name is", __myname__ # <== how do I calculate this at runtime? |
1 2 3 4 | import inspect def foo(): print(inspect.stack()[0][3]) |
Python没有在函数本身中访问函数或函数名的特性。有人提议,但遭到拒绝。如果您不想亲自处理堆栈,则应该根据上下文使用
所发出的拒收通知书为:
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.
有几种方法可以得到相同的结果:
1 2 3 4 5 6 7 8 9 | 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) |
注意,
1 2 3 4 5 6 7 8 | $ 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 |
您可以使用@Andreas Jung所示的方法来获得定义函数的名称,但这可能不是调用函数的名称:
1 2 3 4 5 6 7 8 9 10 11 12 | import inspect def Foo(): print inspect.stack()[0][3] Foo2 = Foo >>> Foo() Foo >>> Foo2() Foo |
我不能说这种区别对你是否重要。
1 | functionNameAsString = sys._getframe().f_code.co_name |
我想要一个非常类似的东西,因为我想把函数名放在一个日志字符串中,它在我的代码中出现了很多地方。可能不是最好的方法,但这里有一种方法可以获得当前函数的名称。
我把这个方便的工具放在附近:
1 2 | import inspect myself = lambda: inspect.stack()[1][3] |
用法:
1 | myself() |
我想
1 2 3 | import inspect def bar(): print("My name is", inspect.stack()[0][3]) |
我找到了一个包装器,它将编写函数名
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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() |
这将打印
my_funky_name
STUB
这实际上是从这个问题的其他答案推导出来的。
这里是我采用的方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 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 |
与使用inspection .stack()相比,这个版本的优势可能是它应该快数千倍(参见Alex Melihoff的文章和关于使用sys._getframe()和使用inspection .stack()的计时)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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() |
在IDE中,代码输出
hello, I'm foo, daddy is
hello, I'm bar, daddy is foo
hello, I'm bar, daddy is
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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()) |
测试:
1 2 3 | a = A() a.test_class_func_name() test_func_name() |
输出:
1 2 | test_class_func_name test_func_name |
这里有一个未来证明的方法。
将@CamHart和@Yuval的建议与@RoshOxymoron的公认答案相结合,可以避免:
因此,我认为这与未来的python版本(在2.7.3和3.3.2上测试过)配合得很好:
1 2 3 4 5 | from __future__ import print_function import inspect def bar(): print("my name is '{}'".format(inspect.currentframe().f_code.co_name)) |
你可以使用装饰:
1 2 3 4 5 6 7 8 | def my_function(name=None): return name def get_function_name(function): return function(name=function.__name__) >>> get_function_name(my_function) 'my_function' |
我照卡姆哈特说的做了:
1 2 3 4 5 | import sys def myFunctionsHere(): print(sys._getframe().f_code.co_name) myFunctionsHere() |
输出:
C:\Python\Python36\python.exe C:/Python/GetFunctionsNames/TestFunctionsNames.py
myFunctionsHereProcess finished with exit code 0
最近,我尝试使用上面的答案从函数的上下文中访问函数的docstring,但是由于上面的问题只返回名称字符串,所以没有成功。
幸运的是,我找到了一个简单的解决方案。如果像我一样,希望引用函数,而不是简单地获取表示名称的字符串,则可以对函数名的字符串应用eval()。
1 2 3 4 | import sys def foo(): """foo docstring""" print(eval(sys._getframe().f_code.co_name).__doc__) |
我使用自己的方法在多重继承场景中安全调用super(我将所有代码)
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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 |
示例用法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | class A(object): def __init__(): super(A, self).__init__() @with_name def test(self): print 'called from A ' safe_super(A, self)() class B(object): def __init__(): super(B, self).__init__() @with_name def test(self): print 'called from B ' safe_super(B, self)() class C(A, B): def __init__(): super(C, self).__init__() @with_name def test(self): print 'called from C ' safe_super(C, self)() |
测试:
1 2 | a = C() a.test() |
输出:
1 2 3 | called from C called from A called from B |
在每个@with_name修饰方法中,您都可以访问self。作为当前函数名。
使用这个(基于#Ron Davis的回答):
1 2 3 4 5 | 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 |