3

考虑以下脚本,它用于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' bars body 会使其工作。

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

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

4

2 回答 2

3

文档中:

如果提供,locals 可以是任何映射对象。请记住,在模块级别,全局变量和局部变量是同一个字典。如果 exec 获得两个单独的对象作为全局对象和局部对象,则代码将被执行,就好像它嵌入在类定义中一样。

并且类定义不会创建封闭范围,注意,这就是为什么你不能在不使用的情况下从另一个方法调用一个方法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
于 2020-10-29T04:24:53.137 回答
0
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
于 2020-10-29T04:41:29.157 回答