Python函数有一个代码对象__code__
。
sys.settrace
跟踪frame
有一个f_code
代码对象。
对于那些作为函数的跟踪器的调用,我如何获得函数对象(及其__annotation__
成员)?
到目前为止,通过反复试验,我有:
if hasattr(frame.f_globals.get(frame.f_code.co_name),"__annotations__"):
这似乎适用于函数,但不适用于类成员函数;更糟糕的是,它将类成员函数与同名的顶级函数混淆。
(我在Python 3.2.3(Xubuntu)上。我看到Python 3.3 inspect
模块有一个signature
函数;它会返回代码对象的注释还是需要它?一个函数对象?)
答案 0 :(得分:5)
通过inspect.getframeinfo
模块。
我的意思是 - 在Python中没有直接的方法 - 大多数时候你可以掌握代码对象,而不必使用函数,它是通过框架的自省。
Inspect的getframeinfo函数确实会返回有关正在运行的帧的一些信息,然后您可以通过获取其名称来检索函数对象。
这是依赖于实现的并且有一些缺点:
>>> import inspect
>>> def a():
... return inspect.currentframe()
...
>>> inspect.getframeinfo(a())
Traceback(filename='<stdin>', lineno=2, function='a', code_context=None, index=None)
>>> b = inspect.getframeinfo(a())
>>> b.function
'a'
另一种方法,但仍然依赖于实现,是使用gc模块(垃圾收集器)来获取所述代码对象的引用。
>>> import gc
>>> from types import FunctionType
>>> def a(): pass
...
>>> code = a.__code__
>>> [obj for obj in gc.get_referrers(code) if isinstance(obj, FunctionType) ][0]
<function a at 0x7f1ef4484500>
>>>
-
这适用于Python 3 - 对于Python 2,应该用__code__
func_code
答案 1 :(得分:0)
您可以检索功能对象作为模块或类的属性:
import inspect
import sys
def frame_to_func(frame):
func_name = frame.f_code.co_name
if "self" in frame.f_locals:
return getattr(frame.f_locals["self"].__class__, func_name)
else:
return getattr(inspect.getmodule(frame), func_name)
def tracefunc(frame, event, arg):
if event in ['call', 'return']:
func_obj = frame_to_func(frame)
print(f"{event} {frame.f_code.co_name} {func_obj.__annotations__}")
def add(x: int, y: int) -> int:
return x+y
if __name__ == '__main__':
sys.settrace(tracefunc)
add(1, 2)
sys.settrace(None)
输出:
call add {'x': <class 'int'>, 'y': <class 'int'>, 'return': <class 'int'>}
此question启发了该解决方案。