如何从 ast.FunctionDef 节点创建函数对象?

How to create a function object from an ast.FunctionDef node?

我正在尝试了解执行 python 代码的过程。假设源有一个函数定义。使用 ast.parse(),我将其解析为一个 ast,它将包含 FunctionDef 节点 class 的一个实例。此节点实例不可调用,与函数对象不同。如何从这个 ast 创建具有所有 dunder 属性的函数对象?

您不能(据我所知)像 FunctionDef 那样编译任意单个 AST 节点。您可以做的是将整个代码片段编译为一个模块,在提供的命名空间中执行它,然后访问它的内容,包括函数。这是一个例子:

import ast

txt = """
def foo(x, y=2):
    z = x*y + 3
    print("z is", z)
    return z**2
"""

tree = ast.parse(txt, mode='exec')
code = compile(tree, filename='blah', mode='exec')
namespace = {}
exec(code, namespace)

现在 namespace 相当于包含给定代码的模块的 __dict__。您可以访问和调用函数:

>>> namespace['foo']
<function foo at 0x00000000023A2B70>
>>> namespace['foo'](2, 3)
z is 9
81

请注意,如果这就是您要做的全部,则根本不需要使用 ast。您可以直接使用 compile(tree, filename='blah', mode='exec') 编译源字符串。事实上,甚至不需要涉及 compile,因为您可以直接使用 exec(txt, namespace) 执行源字符串。如果你的目标只是得到最终的函数对象,你真的不需要访问内部解析和编译步骤;只需在命名空间中执行整个过程,然后从那里获取函数。

如果函数在 class 下,下面的代码会有所帮助 - 导入 ast

txt = """
class MyClass():
  def foo(x, y=2):
      z = x*y + 3
      print("z is", z)
      return z**2
"""

tree = ast.parse(txt, mode='exec')
code = compile(tree, filename='blah', mode='exec')
namespace = {}
exec(code, namespace)
val = "foo"
dict_item = namespace["MyClass"].__dict__.items()
for x,y in list(dict_item):
  if val == x:
    print(x)
    print(y)
    print(type(x))
    print(type(y))