Python 执行产生 NameError 的函数链

Python exec with a function chain producing NameError

考虑以下脚本,它使用 exec 定义两个函数,其中一个调用另一个:

def run_code():
  code = """
def foo():
  print('foo')
  return 1

def bar():
  print('bar calls foo')
  return 1 + foo()

result = bar()
"""

  exec(code, globals(), locals())
  print('Result: {}'.format(locals()['result']))

run_code()

我希望看到以下输出:

bar calls foo
foo
Result: 2

但是,我得到以下输出+堆栈跟踪:

bar calls foo
Traceback (most recent call last):
  File "minimal.py", line 17, in <module>
    run_code()
  File "minimal.py", line 14, in run_code
    exec(code, globals(), locals())
  File "<string>", line 10, in <module>
  File "<string>", line 8, in bar
NameError: name 'foo' is not defined

有趣的是,如果 run_code 的内容被移动到模块级别,那么它工作正常。但是,如果我随后用新的空字典替换 globals()locals(),它会再次中断。我也知道将 def foo 放在 bar 的 body 中会使它起作用。

为什么会出现此错误,正确的解决方法是什么?

(我知道 exec 通常不受欢迎。我使用它是有充分理由的。)

来自documentation

If provided, locals can be any mapping object. Remember that at module level, globals and locals are the same dictionary. If exec gets two separate objects as globals and locals, the code will be executed as if it were embedded in a class definition.

和 class 定义 不创建封闭范围 ,请注意,这就是为什么不使用 self 就不能从另一个方法调用方法的原因。所以只需传递globals()字典。或者将两个相同的字典传递给两个参数。

In [4]: def run_code():
   ...:     code = """
   ...: def foo():
   ...:   print('foo')
   ...:   return 1
   ...:
   ...: def bar():
   ...:   print('bar calls foo')
   ...:   return 1 + foo()
   ...:
   ...: result = bar()
   ...: """
   ...:     namespace = {}
   ...:     exec(code, namespace)
   ...:     print('Result: {}'.format(namespace['result']))
   ...:

In [5]: run_code()
bar calls foo
foo
Result: 2
code = """  
def foo():
  print('foo')
  return 1

def bar():
  global foo;
  print('bar calls foo')
  return 1 + foo()

result = bar()
"""
def run_code():
    exec(code, globals(), locals())
    print('Result: {}'.format(locals()['result']))


run_code()

输出:

bar calls foo
foo
Result: 2