在 Python 中,确定一个函数是否调用另一个函数

dev*_*vtk 2 python introspection

如何以编程方式确定一个函数是否调用另一个函数?我无法修改任何一个功能。

这是我想要的(source_calls_target):

>>> def check():
>>>     pass
>>> def test_check():
>>>     check()
>>> def source_calls_target(source, target):
>>>     # if source() calls target() somewhere, return True
>>>     ???
>>> source_calls_target(test_check, check)
True
>>> source_calls_target(check, test_check)
False
Run Code Online (Sandbox Code Playgroud)

理想情况下,我不想实际调用target().

理想情况下,我想检查target()source. 它可能会或可能不会根据条件语句实际调用它。

eca*_*mur 5

如果您可以保证可以访问源代码,则可以使用ast.parse

import ast
call_names = [c.func.id for c in ast.walk(ast.parse(inspect.getsource(source)))
              if isinstance(c, ast.Call)]
return 'target' in call_names
Run Code Online (Sandbox Code Playgroud)

请注意,调用总是按名称进行的,因此很难(并且可能不可能)判断调用是针对特定函数还是针对另一个同名函数。

在没有源代码的情况下,唯一的方法是通过反汇编:

import dis
def ops(code):
    i, n = 0, len(code)
    while i < n:
        op = ord(code[i])
        i += 1
        if op == dis.EXTENDED_ARG:
            ext = ord(code[i]) + ord(code[i+1])*256
            op = ord(code[i + 2])
            i += 3
        else:
            ext = 0
        if op >= dis.HAVE_ARGUMENT:
            arg = ord(code[i]) + ord(code[i+1])*256 + ext*65536
            i += 2
            yield op, arg
        else:
            yield op, None

source_ops = list(ops(source.func_code.co_code))
Run Code Online (Sandbox Code Playgroud)

问题是实际上无法判断一个函数是在调用另一个函数还是只是加载对它的引用。如果另一个函数被传递给mapreduce等等,那么它将被调用但传递给另一个函数它可能不是。实际上,明智的做法是假设如果函数在,source.func_code.co_names那么它可能会被调用:

'target' in source.func_code.co_names
Run Code Online (Sandbox Code Playgroud)