如何在被调用的方法中获得调用者的方法名?
假设我有两个方法:
def method1(self):
...
a = A.method2()
def method2(self):
...
如果我不想为method1做任何改变,如何获得调用者的名字(在这个例子中,名字是method1)在method2?
如何在被调用的方法中获得调用者的方法名?
假设我有两个方法:
def method1(self):
...
a = A.method2()
def method2(self):
...
如果我不想为method1做任何改变,如何获得调用者的名字(在这个例子中,名字是method1)在method2?
当前回答
您可以使用装饰器,而不必使用stacktrace
如果您想在类中修饰一个方法
import functools
# outside ur class
def printOuterFunctionName(func):
@functools.wraps(func)
def wrapper(self):
print(f'Function Name is: {func.__name__}')
func(self)
return wrapper
class A:
@printOuterFunctionName
def foo():
pass
你可以删除functools, self,如果它是过程性的
其他回答
Python的Logging库使用sys._getframe()的替代方法来查找调用者信息。这个想法是这样的:
引发一个异常 立即在Except子句中捕获它 使用系统。获取Traceback帧(tb_frame)。 从tb_frame使用f_back获取上一个调用者的帧。 从上一个调用者的帧中获取在该帧中执行的代码对象。 在我们的示例代码中,执行的是method1(不是method2)。 从获得的代码对象中,获取对象的名称——这是示例中调用者方法的名称。
下面是解决问题的示例代码:
def method1():
method2()
def method2():
try:
raise Exception
except Exception:
frame = sys.exc_info()[2].tb_frame.f_back
print("method2 invoked by: ", frame.f_code.co_name)
# Invoking method1
method1()
输出:
method2 invoked by: method1
Frame有各种各样的细节,包括行号、文件名、参数计数、参数类型等等。该解决方案也可以跨类和模块工作。
代码:
#!/usr/bin/env python
import inspect
called=lambda: inspect.stack()[1][3]
def caller1():
print "inside: ",called()
def caller2():
print "inside: ",called()
if __name__=='__main__':
caller1()
caller2()
输出:
shahid@shahid-VirtualBox:~/Documents$ python test_func.py
inside: caller1
inside: caller2
shahid@shahid-VirtualBox:~/Documents$
我提出了一个稍长的版本,试图构建一个完整的方法名称,包括模块和类。
https://gist.github.com/2151727(修订版9CCCBF)
# Public Domain, i.e. feel free to copy/paste
# Considered a hack in Python 2
import inspect
def caller_name(skip=2):
"""Get a name of a caller in the format module.class.method
`skip` specifies how many levels of stack to skip while getting caller
name. skip=1 means "who calls me", skip=2 "who calls my caller" etc.
An empty string is returned if skipped levels exceed stack height
"""
stack = inspect.stack()
start = 0 + skip
if len(stack) < start + 1:
return ''
parentframe = stack[start][0]
name = []
module = inspect.getmodule(parentframe)
# `modname` can be None when frame is executed directly in console
# TODO(techtonik): consider using __main__
if module:
name.append(module.__name__)
# detect classname
if 'self' in parentframe.f_locals:
# I don't know any way to detect call from the object method
# XXX: there seems to be no way to detect static method call - it will
# be just a function call
name.append(parentframe.f_locals['self'].__class__.__name__)
codename = parentframe.f_code.co_name
if codename != '<module>': # top level usually
name.append( codename ) # function or a method
## Avoid circular refs and frame leaks
# https://docs.python.org/2.7/library/inspect.html#the-interpreter-stack
del parentframe, stack
return ".".join(name)
我将使用inspect.currentframe().f_back.f_code.co_name。它的用法在之前的回答中没有涉及,主要有三种类型:
一些先前的答案使用inspect。堆栈,但它是众所周知的太慢。 一些先前的回答使用sys。_getframe是一个内部私有函数,因为它有前导下划线,所以不鼓励使用它。 一个先前的答案使用inspect.getouterframes(inspect.currentframe(), 2)[1][3],但它完全不清楚[1][3]正在访问什么。
import inspect
from types import FrameType
from typing import cast
def demo_the_caller_name() -> str:
"""Return the calling function's name."""
# Ref: https://stackoverflow.com/a/57712700/
return cast(FrameType, cast(FrameType, inspect.currentframe()).f_back).f_code.co_name
if __name__ == '__main__':
def _test_caller_name() -> None:
assert demo_the_caller_name() == '_test_caller_name'
_test_caller_name()
注意cast(FrameType, frame)是用来满足mypy的。
致谢:回复请留言1313e。
我找到了一种方法,如果你要跨越类,并且想要方法所属的类和方法。这需要一些提取工作,但它是有意义的。这在Python 2.7.13中有效。
import inspect, os
class ClassOne:
def method1(self):
classtwoObj.method2()
class ClassTwo:
def method2(self):
curframe = inspect.currentframe()
calframe = inspect.getouterframes(curframe, 4)
print '\nI was called from', calframe[1][3], \
'in', calframe[1][4][0][6: -2]
# create objects to access class methods
classoneObj = ClassOne()
classtwoObj = ClassTwo()
# start the program
os.system('cls')
classoneObj.method1()