加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Python > 正文

为什么Python exec中的模块级变量无法访问?

发布时间:2020-12-16 23:35:53 所属栏目:Python 来源:网络整理
导读:我试图在 project中使用Python的执行程序来执行嵌入式Python代码. 我遇到的问题是,在exec语句中的模块级别创建的变量不能从同一模块中定义的函数访问. 假设你有以下Python程序: x = 5def foo(): print xfoo() 如果将上述四行放在一个文件中并运行它,那么它
我试图在 project中使用Python的执行程序来执行嵌入式Python代码.

我遇到的问题是,在exec语句中的模块级别创建的变量不能从同一模块中定义的函数访问.

假设你有以下Python程序:

x = 5
def foo():
    print x
foo()

如果将上述四行放在一个文件中并运行它,那么它将无所谓.

但是,如果您尝试从exec语句中运行相同的代码,它将无法正常工作.

这是我们以前的程序,在一个exec语句里面:

import __builtin__

global_env = {'__builtins__': __builtin__}
local_env = dict()

exec """
x = 5
def foo():
    print x
foo()
""" in global_env,local_env

执行时,而不是工作,它会产生以下错误:

Traceback (most recent call last):
  File "lab.py",line 94,in <module>
    """ in global_env,local_env
  File "<string>",line 5,in <module>
  File "<string>",line 4,in foo
NameError: global name 'x' is not defined

我认为模块级变量存储在全局范围内,但似乎至少在exec中,它们不是.

例如,在上一个示例中,如果将foo()的调用替换为:

print global_env
print local_env

你得到:

{'__builtins__': <module '__builtin__' (built-in)>}
{'x': 5,'foo': <function foo at 0x102c12938>}

所以在模块级(包括x)中定义的任何东西都存储在本地()中.

但是除了exec语句的模块级以外,从任何地方访问x是不可能的.特别是,如上所述,x的本地范围对同一个exec语句中定义的函数是不可见的.

解决方法

我找到了解决这个问题的两种方法,并使x再次访问.

第一个在函数中使用全局关键字:

exec """
x = 5
def foo():
    global x
    print x
foo()
""" in global_env,local_env

第二个在exec中使用与全局变量()和locals()相同的字典:

exec """
x = 5
def foo():
    print x
foo()
""" in global_env

但是,这些只是解决原始问题的半修复/解决方法.

所以我的问题是:为什么exec中的模块级变量存储在本地,为什么从模块级到任何地方都不可访问?

一些密切相关的StackOverflow帖子:

> globals and locals in python exec()
> Cannot change global variables in a function through an exec() statement?

解决方法

要了解发生了什么,您需要非常仔细地阅读 the docs.关键部分说:

If two separate objects are given as globals and locals,the code will be executed as if it were embedded in a class definition.

这意味着本地的赋值将变成本地命名空间(相当于类级变量),但如果函数(即方法)尝试引用本地(类)变量,则不会成为闭包.

将您的代码与:

class Test(object):
    x = 1
    def foo():
        print x
    foo()

同样的原因,你会得到同样的错误. foo不是一个闭包,所以它尝试在全局命名空间(不成功)中引用x.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读