为了账号安全,请及时绑定邮箱和手机立即绑定

Python exec 的函数链产生 NameError

Python exec 的函数链产生 NameError

梵蒂冈之花 2024-01-27 15:06:08
考虑以下脚本,它用于exec定义两个函数,其中一个调用另一个:def run_code():  code = """def foo():  print('foo')  return 1def bar():  print('bar calls foo')  return 1 + foo()result = bar()"""  exec(code, globals(), locals())  print('Result: {}'.format(locals()['result']))run_code()我希望看到以下输出:bar calls foofooResult: 2但相反,我得到以下输出+堆栈跟踪:bar calls fooTraceback (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 barNameError: name 'foo' is not defined有趣的是,如果将 的内容run_code移至模块级别,那么它就可以正常工作。但是,如果我随后用新的空字典替换globals()or locals(),它会再次中断。我也知道,放进def foo体内bar就能发挥作用。为什么会发生此错误?正确的解决方法是什么?(我知道这exec通常会让人皱眉。我使用它是有充分理由的。)
查看完整描述

2 回答

?
不负相思意

TA贡献1777条经验 获得超10个赞

从文档中:

如果提供的话,局部变量可以是任何映射对象。请记住,在模块级别,全局变量和局部变量是相同的字典。如果 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


查看完整回答
反对 回复 2024-01-27
?
元芳怎么了

TA贡献1798条经验 获得超7个赞

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


查看完整回答
反对 回复 2024-01-27
  • 2 回答
  • 0 关注
  • 40 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信