我想使用自省功能从函数本身存储为函数调用键入的确切字符串(我不能/不想破解命令行解释器-因此,例如,从readline或什么都不是我想要的)。
假设,如果用户键入:
"W" != "w"
我想获取通话字符串(即>>> myfunc('a', 'b', 1, mykwarg='hello')
)
来自myfunc('a', 'b', 1, mykwarg='hello')
内部的代码。
我可以制作这样的东西:
myfunc
我得到:
def myfunc(a,b,c,mykwarg=None):
frame = inspect.currentframe()
sig = inspect.signature(myfunc)
args = []
for param in sig.parameters.values():
if param.name in frame.f_locals:
args.append(f"{param.name}={str(frame.f_locals[param.name])}")
cmd = f"{frame.f_code.co_name}({','.join(args)})"
print(cmd)
这不是用户键入的确切内容。另外,我希望还有更多 健壮且不太“ hackish”尝试...
用例:我希望能够将库中的命令调用与其结果相关联。我不想为每个函数硬编码命令调用存储,我更喜欢使用装饰器或类似的东西。通过REPL可以很容易地做到这一点,但是我不希望依赖它(例如,如果用户从其自己的程序中调用该函数,它仍然应该能够将命令调用与结果相关联)。>
答案 0 :(得分:0)
最后,我回答了我自己的问题,希望有一天能对其他人有所帮助。
我决定尝试采用dis
的方式,即“反汇编”的Python代码对象
调用我的函数的外部框架,以了解如何调用它
重建命令行:
import dis
import inspect
import io
import ast
import re
def get_function_call_string():
in_func = False
args=[]
kwargs=[]
func_name = inspect.stack()[1][3]
frame = inspect.currentframe().f_back.f_back
dis_output = io.StringIO()
dis.dis(frame.f_code, file=dis_output)
for line in dis_output.getvalue().split('\n'):
instr = re.findall(r'^.*\s([A-Z_]+)\s*', line)[0]
if instr.startswith("CALL_FUNCTION") and in_func:
break
elif instr.startswith('LOAD_'):
name = re.findall(r'^.*\s\((.+)\)$', line)[0]
if in_func:
if name.startswith('('):
kwargs = ast.literal_eval(name)
else:
args.append(name)
elif name == func_name:
in_func = True
kwargs = [f"{a}={args.pop()}" for a in kwargs]
return f"{func_name}({', '.join(args)}{', ' if kwargs else ''}{', '.join(kwargs)})"
示例:
>>> def f(a,b,arg="toto"):
print(get_function_call_string())
>>> f(1,"test","example")
f(1, 'test', 'example')
>>> f(1, "test", arg="hello")
(1, 'test', arg='hello')
这不是一个完整的答案,因为它无法处理某些参数类型,例如 dict或list ...我可能会继续这样做或改变主意并做不同的事情。