python - 获取 Python 函数的调用字符串,如在命令行中键入的那样

标签 python read-eval-print-loop introspection

我想使用内省(introspection)从函数本身存储为函数调用键入的确切字符串(我不能/不想破解命令行解释器——因此,例如从 readline 或任何不是我要找的东西)。

假设,如果用户输入:

>>> 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)

我得到:

>>> myfunc('a', 'b', 1, mykwarg='hello')
myfunc(a=a,b=b,c=1,mykwarg=hello)

这不完全是用户输入的内容。另外,我希望有更多的东西 健壮且不那么“老套”的尝试...

用例:我希望能够将来 self 的库的命令调用与其结果相关联。我不想为每个函数硬编码命令调用存储,我更愿意使用装饰器或类似的东西。这可能在 REPL 中更容易做到,但我不想依赖它(比如,如果用户从自己的程序调用该函数,它仍然应该能够将命令调用与结果相关联)。

最佳答案

最后我回答了我自己的问题,希望有一天它能对其他人有所帮助。

我决定尝试采用 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...我可能会继续这样做,或者改变主意,做不同的事情。

关于python - 获取 Python 函数的调用字符串,如在命令行中键入的那样,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56003055/

相关文章:

python - 如何将 PIL 图像转换为字符串,然后将其转换回 PIL 图像?转换将在不保存到新文件的情况下完成

objective-c - 如何在 Objective-C 中列出对象的所有字段?

java - 实例化一个没有默认构造函数的类

python - "Unsorting"快速排序

python - 将绘图中的图例设置为 Bokeh 中的列名称

python - python 中更新周数的函数

python - 为什么 python 解释器提示 ... 注释 "#"?

javascript - 为什么这段 JavaScript 代码在控制台上打印 "undefined"?

emacs - pretty-print 和扩展

python - django - 具有模型类如何获取所有字段的列表、它们的类型和传递的参数?