繁体   English   中英

python exec()中的全局变量和局部变量

[英]globals and locals in python exec()

我正在尝试使用exec运行一段python代码。

my_code = """
class A(object):
  pass

print 'locals: %s' % locals()
print 'A: %s' % A

class B(object):
  a_ref = A
"""

global_env = {}
local_env = {}
my_code_AST = compile(my_code, "My Code", "exec")
exec(my_code_AST, global_env, local_env)

print local_env

这导致以下输出

locals: {'A': <class 'A'>}
A: <class 'A'>
Traceback (most recent call last):
  File "python_test.py", line 16, in <module>
    exec(my_code_AST, global_env, local_env)
  File "My Code", line 8, in <module>
  File "My Code", line 9, in B
NameError: name 'A' is not defined

但是,如果我将代码更改为此-

my_code = """
class A(object):
  pass

print 'locals: %s' % locals()
print 'A: %s' % A

class B(A):
  pass
"""

global_env = {}
local_env = {}
my_code_AST = compile(my_code, "My Code", "exec")
exec(my_code_AST, global_env, local_env)

print local_env

然后工作正常-提供以下输出-

locals: {'A': <class 'A'>}
A: <class 'A'>
{'A': <class 'A'>, 'B': <class 'B'>}

显然,A存在并且可以访问-第一段代码出了什么问题? 我正在使用2.6.5,欢呼声,

科林

*更新1 *

如果我检查类中的locals()-

my_code = """
class A(object):
  pass

print 'locals: %s' % locals()
print 'A: %s' % A

class B(object):
  print locals()
  a_ref = A
"""

global_env = {}
local_env = {}
my_code_AST = compile(my_code, "My Code", "exec")
exec(my_code_AST, global_env, local_env)

print local_env

然后很明显,locals()在两个地方都不相同-

locals: {'A': <class 'A'>}
A: <class 'A'>
{'__module__': '__builtin__'}
Traceback (most recent call last):
  File "python_test.py", line 16, in <module>
    exec(my_code_AST, global_env, local_env)
  File "My Code", line 8, in <module>
  File "My Code", line 10, in B
NameError: name 'A' is not defined

但是,如果我这样做,就没有问题-

def f():
  class A(object):
    pass

  class B(object):
    a_ref = A

f()

print 'Finished OK'

*更新2 *

好的,所以这里的文档-http: //docs.python.org/reference/executionmodel.html

在我看来,“ A”应该作为可执行语句(作为B的定义)中的自由变量提供,并且这种情况在我们调用上述f()时发生,但在使用exec()时不发生。 使用以下代码可以更容易地显示出来:

my_code = """
class A(object):
  pass

print 'locals in body: %s' % locals()
print 'A: %s' % A

def f():
  print 'A in f: %s' % A

f()

class B(object):
  a_ref = A
"""

哪个输出

locals in body: {'A': <class 'A'>}
A: <class 'A'>
Traceback (most recent call last):
  File "python_test.py", line 20, in <module>
    exec(my_code_AST, global_env, local_env)
  File "My Code", line 11, in <module>
  File "My Code", line 9, in f
NameError: global name 'A' is not defined

因此,我想一个新的问题是-为什么这些局部变量不作为函数和类定义中的自由变量公开-似乎是一个非常标准的关闭方案。

好吧,我认为这可能是实现错误,也可能是未经证明的设计决策。 问题的症结在于模块范围中的名称绑定操作应绑定到全局变量。 实现的方法是,在模块级别,globals()是locals()(在解释器中尝试该值),因此,当您进行任何名称绑定时,它会像往常一样将其分配给locals( )字典,它也是全局变量,因此创建了全局变量。

查找变量时,首先检查当前的本地变量,如果未找到名称,则递归检查包含范围的本地变量变量名称,直到找到变量或到达模块作用域为止。 如果达到此目的,则检查全局变量,该全局变量应该是模块作用域的本地变量。

>>> exec(compile("import sys\nprint sys._getframe().f_code.co_name", "blah", "exec"), {}, {})
<module>
>>> exec("a = 1\nclass A(object):\n\tprint a\n", {}, {})
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 2, in <module>
  File "<string>", line 3, in A
NameError: name 'a' is not defined
>>> d = {}
>>> exec("a = 1\nclass A(object):\n\tprint a\n", d,d)
1

此行为是继承起作用的原因(名称查找使用了代码对象的作用域locals(),其中确实包含A)。

最后,这是CPython实现中的一个丑陋的骇客,专门对全局变量进行查找。 它还会导致一些荒谬的人为情况-例如:

>>> def f():
...     global a
...     a = 1
...
>>> f()
>>> 'a' in locals()
True

请注意,这是我在阅读python语言参考的第4.1节(命名和绑定)时基于与解释器混淆的所有推断。 尽管这不是确定的(我还没有打开CPython的源代码),但我相当确定我对行为是正确的。

print locals()globals() ,您将找到exec引发“未定义”异常的原因,您可以尝试执行此操作

d = dict(locals(), **globals())
exec (code, d, d)

如果您的问题是如何使exec语句的行为类似于文件作用域,我将在链接的问题和错误中遵循一些提示,并通过为全局变量和局部变量传递单个字典来使其工作。 显然,文件作用域是一种特殊情况,其中本地声明会自动放置在全局作用域中。

exec code in dict()
my_code = """
class A(object):
    pass

class B(object):
    a = A
"""

my_code_AST = compile(my_code, "My Code", "exec")
extra_global = "hi"
global_env = {}
exec my_code_AST in global_env
print "global_env.keys() =", global_env.keys()
print "B.a =", global_env["B"].a

版画

global_env.keys() = ['__builtins__', 'A', 'B']
B.a = <class 'A'>

霍克特,你说,

我想要使​​用类似locals的主要原因是要获取代码字符串中定义的所有内容,而不要将python放入全局变量中的所有其他内容。

使用exec时,如果您的全局变量没有定义__builtins__ ,则exec将一个项目__builtins__添加到您的全局变量中,因此您会获得A,B和__builtins__ __builtins__本身就是一个大字典,但它总是同一个元素删除(只要你等到你的代码被删除之前使用完!)。 ()下记录的exec 这里

内置函数下的eval文档说

如果存在globals字典并且缺少' builtins ',则在解析表达式之前将当前的globals复制到globals中。

但实际上似乎只复制了__builtins__

(还有其他人说的话:要么将全局变量和本地变量设置为相同, exec my_code_AST in global_envexec my_code_AST in global_env而无需单独的local_env。)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM