How to get the caller's method name in the called method?
Python:如何在被调用的方法中获取调用者的方法名?
假设我有两种方法:
1 2 3 4 5 6 | def method1(self): ... a = A.method2() def method2(self): ... |
如果我不想对method1进行任何更改,如何在method2中获取调用者的名称(在此示例中,名称为method1)?
inspect.getframeinfo和
1 2 3 4 5 6 7 8 9 10 | >>> import inspect >>> def f1(): f2() ... >>> def f2(): ... curframe = inspect.currentframe() ... calframe = inspect.getouterframes(curframe, 2) ... print('caller name:', calframe[1][3]) ... >>> f1() caller name: f1 |
这种内省旨在帮助调试和开发;不建议将其用于生产功能目的。
更短的版本:
1 2 3 4 5 6 7 8 | import inspect def f1(): f2() def f2(): print 'caller name:', inspect.stack()[1][3] f1() |
(感谢@Alex和Stefaan Lippen)
这似乎工作得很好:
1 2 | import sys print sys._getframe().f_back.f_code.co_name |
我想出了一个稍微长一点的版本,试图建立一个完整的方法名称,包括模块和类。
https://gist.github.com/2151727(rev 9cccbf)
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 33 34 35 36 37 38 39 40 | # 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) |
上面的东西融合了一点点。但这是我对它的抨击。
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 | def print_caller_name(stack_size=3): def wrapper(fn): def inner(*args, **kwargs): import inspect stack = inspect.stack() modules = [(index, inspect.getmodule(stack[index][0])) for index in reversed(range(1, stack_size))] module_name_lengths = [len(module.__name__) for _, module in modules] s = '{index:>5} : {module:^%i} : {name}' % (max(module_name_lengths) + 4) callers = ['', s.format(index='level', module='module', name='name'), '-' * 50] for index, module in modules: callers.append(s.format(index=index, module=module.__name__, name=stack[index][3])) callers.append(s.format(index=0, module=fn.__module__, name=fn.__name__)) callers.append('') print(' '.join(callers)) fn(*args, **kwargs) return inner return wrapper |
使用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | @print_caller_name(4) def foo(): return 'foobar' def bar(): return foo() def baz(): return bar() def fizz(): return baz() fizz() |
输出是
1 2 3 4 5 6 | level : module : name -------------------------------------------------- 3 : None : fizz 2 : None : baz 1 : None : bar 0 : __main__ : foo |
我找到了一种方法,如果你跨越类并希望方法所属的类和方法。它需要一些提取工作,但它是重点。这适用于Python 2.7.13。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | import inspect, os class ClassOne: def method1(self): classtwoObj.method2() class ClassTwo: def method2(self): curframe = inspect.currentframe() calframe = inspect.getouterframes(curframe, 4) print ' I 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() |
你可以打印一个功能列表,如回答这里https://stackoverflow.com/a/56897183/4039061
1 2 | import inspect;print(*[' \x1b[0;36;1m| \x1b[0;32;1m{:25}\x1b[0;36;1m| \x1b[0;35;1m{}'.format(str(x.function), x.filename+'\x1b[0;31;1m:'+str(x.lineno)+'\x1b[0m') for x in inspect.stack()]) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | #!/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$ |