ast 执行在函数与模块范围内产生不同的结果

ast execution produces different result in a function vs module scope

编辑:问题与 ast 模块无关。

只需使用exec即可重现:

y = None

exec("y = 5.0")
print(y)  # prints 5.0

def foo():
    y = None

    exec("y = 5.0")
    print(y)

foo()  # prints None

原题:

我正在使用 ast 模块以编程方式生成代码。我有以下有效的代码:

import ast

num = ast.Num(n=5.)
y = None
assign = ast.Assign(targets=[ast.Name(id='y', ctx=ast.Store())], value=num)
tree = ast.Module(body=[assign], type_ignores=[])
ast.fix_missing_locations(tree)
c = compile(tree, filename="", mode="exec")
exec(c)  # replaces the value of 'y' with 5.0

print(y) # prints 5.0

但是,一旦我将这段代码包装在一个函数中,它就停止工作了:

import ast

def foo():
    num = ast.Num(n=5.)

    y = None
    assign = ast.Assign(targets=[ast.Name(id='y', ctx=ast.Store())], value=num)
    tree = ast.Module(body=[assign], type_ignores=[])
    ast.fix_missing_locations(tree)
    c = compile(tree, filename="", mode="exec")
    exec(c)

    print(y)

foo()  # prints None

这是我第一次看到 python 代码在移入函数后表现不同。我已经检查过,作业也没有将 y 放入模块(本地)中:

print(y) # NameError: name 'y' is not defined

变量 Y 在函数范围内声明,在函数范围外不可用。如果您希望 Y 可用 post 函数调用 return 它或使用全局变量。

更新: 请参阅我关于 exec 和范围的评论:exec() and variable scope

在函数中时,您可以将赋值捕获到任何字典中,该字典将作为已执行语句的作用域:

def foo():
    scope = {}
    exec("y = 5.0", scope)
    print(scope['y'])

foo()  # prints 5.0