从FrameInfo或python中的frame获取函数签名

从FrameInfo或python中的frame获取函数签名,python,traceback,Python,Traceback,在用python编写自己的异常钩子时,我想到了使用inspect-模块来为自己提供有关如何调用函数的更多信息 这意味着函数的签名以及传递给它的参数 import inspect frame_infos = inspect.trace() # get the FrameInfos for f_idx, f_info in enumerate(frame_infos): frame_dict.update(f_info.frame.f_locals) # update namespace

在用python编写自己的异常钩子时,我想到了使用
inspect
-模块来为自己提供有关如何调用函数的更多信息

这意味着函数的签名以及传递给它的参数

import inspect

frame_infos = inspect.trace() # get the FrameInfos

for f_idx, f_info in enumerate(frame_infos):
    frame_dict.update(f_info.frame.f_locals) # update namespace with deeper frame levels
    #Output basic Error-Information
    print(f'  File "{f_info.filename}", line {f_info.lineno}, in {f_info.function}')
    for line in f_info.code_context:
        print(f'    {line.strip()}')

    ########################################################
    # show signature and arguments 1 level deeper
    if f_idx+1 < len(frame_infos): 
        func_name = frame_infos[f_idx+1].function #name of the function
        try:
            func_ref = frame_dict[func_name] # look up in namespace
            sig = inspect.signature(func_ref) # call signature for function_reference
        except KeyError: sig = '(signature unknown)'
        print(f'    {func_name} {sig}\n')
        print(f'    {frame_infos[f_idx+1].frame.f_locals}\n')
输出:

File "C:/test/errorHandler.py", line 136, in <module>
    test1(5)
    test1 (x:int, y:tuple=0) -> list
    {'y': 0, 'x': 5}
File "C:/test/errorHandler.py", line 130, in test1
    return test2(y, b=x, help=0)
    test2 (a, *args, b, **kwargs)
    {'kwargs': {'help': 0}, 'args': (), 'b': 5, 'a': 0}
File "C:/test/errorHandler.py", line 133, in test2
    return a + b / 0
Traceback (most recent call last):
  File "C:/test/errorHandler.py", line 142, in <module>
    try: foo(0, 1, test=True)
    > foo (a, b, **kwargs)
    -> 'b': 'fail'
  File "C:/test/errorHandler.py", line 140, in foo
    return 0 / 0
ZeroDivisionError: division by zero
文件“C:/test/errorHandler.py”,第136行,在
测试1(5)
test1(x:int,y:tuple=0)->list
{'y':0,'x':5}
文件“C:/test/errorHandler.py”,第130行,在test1中
返回test2(y,b=x,help=0)
测试2(a,*args,b,**kwargs)
{'kwargs':{'help':0},'args':(),'b':5,'a':0}
文件“C:/test/errorHandler.py”,第133行,在test2中
返回a+b/0
但是,一旦离开1个文件,就不能将函数名映射到基本名称空间

文件1:
导入文件2;尝试:file2.foo()除了:…

文件2:
导入文件3;def foo():file3.foo()

文件3:
def foo():返回0/0

因此,本质上,我正在寻找一种从
FrameInfo
frame
-对象获取函数(如
)的方法,但我看到的唯一信息是名称、文件和行
(我不喜欢通过查看源文件中特定行来获取签名的想法。)

到目前为止,最好的参考是,但我还没有找到有用的东西。

基于,我找到了恢复签名的解决方案

使用
gc
(垃圾收集器)功能,可以搜索直接引用特定对象的所有对象

通过帧的
f_code
提供的code对象,您可以使用此函数查找帧,也可以使用此函数查找帧

code_obj = frame.f_code
import gc #garbage collector
print(gc.get_referrers(code_obj))
# [<function foo at 0x0000020F758F4EA0>, <frame object at 0x0000020F75618CF8>]
现在可以在过滤对象上使用


Disclamer来自:

此函数将仅定位支持垃圾收集的容器;将找不到引用其他对象但不支持垃圾回收的扩展类型。


完整代码示例: 输出:

File "C:/test/errorHandler.py", line 136, in <module>
    test1(5)
    test1 (x:int, y:tuple=0) -> list
    {'y': 0, 'x': 5}
File "C:/test/errorHandler.py", line 130, in test1
    return test2(y, b=x, help=0)
    test2 (a, *args, b, **kwargs)
    {'kwargs': {'help': 0}, 'args': (), 'b': 5, 'a': 0}
File "C:/test/errorHandler.py", line 133, in test2
    return a + b / 0
Traceback (most recent call last):
  File "C:/test/errorHandler.py", line 142, in <module>
    try: foo(0, 1, test=True)
    > foo (a, b, **kwargs)
    -> 'b': 'fail'
  File "C:/test/errorHandler.py", line 140, in foo
    return 0 / 0
ZeroDivisionError: division by zero
回溯(最近一次呼叫最后一次):
文件“C:/test/errorHandler.py”,第142行,在
try:foo(0,1,test=True)
>foo(a、b、**kwargs)
->“b”:“失败”
文件“C:/test/errorHandler.py”,第140行,在foo中
返回0/0
ZeroDivision错误:被零除
你不能相信这一点,但这是另一个问题的问题


链接: 以下是一些链接,如果你想自己研究:


不带检查模块的任何其他选项也将受到欢迎
def foo (a, b, **kwargs):
    del a, kwargs
    b = 'fail'
    return 0/0

try: foo(0, 1, test=True)
except: ERROR_Printer_Inspection()
Traceback (most recent call last):
  File "C:/test/errorHandler.py", line 142, in <module>
    try: foo(0, 1, test=True)
    > foo (a, b, **kwargs)
    -> 'b': 'fail'
  File "C:/test/errorHandler.py", line 140, in foo
    return 0 / 0
ZeroDivisionError: division by zero