Python 获取函数或源代码中调用的所有函数

Python 获取函数或源代码中调用的所有函数,python,python-3.x,metaprogramming,Python,Python 3.x,Metaprogramming,最初我认为我必须解析函数的源代码才能得到它调用的所有函数,但即使这样,我也只能得到函数的名称,而不是函数本身 然后我发现了一些与我类似的问题,例如: 尽管所有其他答案都提供了返回函数名列表的解决方案,但它们并不返回实际函数本身。我想得到一个函数中调用的函数列表,或者源代码作为实际函数的列表,这可能吗?我应该使用ast解决方案,但以某种方式将astFunctionDef对象转换为function对象吗?或者这可以用disdis来完成吗?以下是我目前掌握的情况: import dis def li

最初我认为我必须解析函数的源代码才能得到它调用的所有函数,但即使这样,我也只能得到函数的名称,而不是函数本身

然后我发现了一些与我类似的问题,例如:

尽管所有其他答案都提供了返回函数名列表的解决方案,但它们并不返回实际函数本身。我想得到一个函数中调用的函数列表,或者源代码作为实际函数的列表,这可能吗?我应该使用
ast
解决方案,但以某种方式将
ast
FunctionDef对象转换为function对象吗?或者这可以用dis
dis
来完成吗?以下是我目前掌握的情况:

import dis
def list_func_calls(fn):
    funcs = []
    bytecode = dis.Bytecode(fn)
    instrs = list(reversed([instr for instr in bytecode]))
    for (ix, instr) in enumerate(instrs):
        if instr.opname == "CALL_FUNCTION":
            load_func_instr = instrs[ix + instr.arg + 1]
            funcs.append(load_func_instr.argval)

    return ["%d. %s" % (ix, funcname) for (ix, funcname) in enumerate(reversed(funcs), 1)]

def a():
    print(b())

def b():
    return 'hi'

list_func_calls(a)
我可以想象,从字节码中获取被调用的函数可能会很困难,但我真的不知道,我不太喜欢这个函数,但我想回去:

[<function print>, <function __main__.b()>]
[,]

这种事情可能吗?

被调用函数的名称就是字节码实际包含的全部内容。该名称在运行时被查找;您也可以使用类似于
globals()[name]
(假设所分析的函数与您的代码位于同一个模块中)的方法执行相同的操作。另外:您的代码只能在特别简单的情况下成功地找到被调用函数的名称。如果函数的任何参数都是表达式,而不是简单的变量或文字(因此需要多个字节码操作才能推送到堆栈上),那么您就会找错地方了。@jasonharper谢谢,知道了这一点,现在我的直觉好多了。每个函数都有一个
\uuuu globals\uuuu
属性,我可以使用它来一致地获得
[name]
的函数吗?是的,
\uuuu globals\uuuu
应该适用于被调用函数被全局名称引用的情况。对于没有全局名称的嵌套函数、lambda、方法等,您仍然会遇到问题。@jasonharper有什么解决方案吗?当然,除了暴力解析方法之外……您还可以通过额外的工作来处理其他情况,但这最终不是一个可解决的问题——在调用函数的过程中,存在太多的运行时变化空间。即使在按名称调用全局函数的简单情况下,也可以在分析调用函数的时间和实际调用函数的时间之间重新分配该名称。或者考虑<代码>随机选择。(MyListFox函数)()< /C> >在这种情况下,您希望代码返回什么?被调用的函数的名称实际上是字节码所包含的所有名称。该名称在运行时被查找;您也可以使用类似于
globals()[name]
(假设所分析的函数与您的代码位于同一个模块中)的方法执行相同的操作。另外:您的代码只能在特别简单的情况下成功地找到被调用函数的名称。如果函数的任何参数都是表达式,而不是简单的变量或文字(因此需要多个字节码操作才能推送到堆栈上),那么您就会找错地方了。@jasonharper谢谢,知道了这一点,现在我的直觉好多了。每个函数都有一个
\uuuu globals\uuuu
属性,我可以使用它来一致地获得
[name]
的函数吗?是的,
\uuuu globals\uuuu
应该适用于被调用函数被全局名称引用的情况。对于没有全局名称的嵌套函数、lambda、方法等,您仍然会遇到问题。@jasonharper有什么解决方案吗?当然,除了暴力解析方法之外……您还可以通过额外的工作来处理其他情况,但这最终不是一个可解决的问题——在调用函数的过程中,存在太多的运行时变化空间。即使在按名称调用全局函数的简单情况下,也可以在分析调用函数的时间和实际调用函数的时间之间重新分配该名称。或者考虑<代码>随机选择(MyListFoScess)() -在这种情况下,您希望代码返回什么?