python exec() 中的全局变量和局部变量 [英] globals and locals in python exec()

查看:305
本文介绍了python exec() 中的全局变量和局部变量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

my_code = """A类(对象):经过打印 'locals: %s' % locals()打印 'A: %s' % AB类(对象):a_ref = A"""global_env = {}local_env = {}my_code_AST = compile(my_code, "我的代码", "exec")exec(my_code_AST, global_env, local_env)打印 local_env

结果如下

locals: {'A': }A:<A"类>回溯(最近一次调用最后一次): 中的文件python_test.py",第 16 行exec(my_code_AST, global_env, local_env)文件我的代码",第 8 行,在 <module> 中.文件我的代码",第 9 行,在 B 中NameError:未定义名称A"

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

my_code = """A类(对象):经过打印 'locals: %s' % locals()打印 'A: %s' % AB(A)类:经过"""global_env = {}local_env = {}my_code_AST = compile(my_code, "我的代码", "exec")exec(my_code_AST, global_env, local_env)打印 local_env

然后它工作正常 - 给出以下输出 -

locals: {'A': }A:<A"类>{'A':,'B':}

显然 A 存在且可访问 - 第一段代码出了什么问题?我正在使用 2.6.5,干杯,

科林

* 更新 1 *

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

my_code = """A类(对象):经过打印 'locals: %s' % locals()打印 'A: %s' % AB类(对象):打印当地人()a_ref = A"""global_env = {}local_env = {}my_code_AST = compile(my_code, "我的代码", "exec")exec(my_code_AST, global_env, local_env)打印 local_env

然后很明显 locals() 在两个地方都不一样 -

locals: {'A': }A:<A"类>{'__module__': '__builtin__'}回溯(最近一次调用最后一次): 中的文件python_test.py",第 16 行exec(my_code_AST, global_env, local_env)文件我的代码",第 8 行,在 <module> 中.文件我的代码",第 10 行,在 B 中NameError:未定义名称A"

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

def f():A类(对象):经过B类(对象):a_ref = AF()打印完成OK"

* 更新 2 *

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

'类定义是可以使用和定义名称的可执行语句.这些引用遵循名称解析的正常规则.类定义的命名空间成为类的属性字典.在类范围内定义的名称在方法中不可见.'

在我看来,'A' 应该作为 B 的定义的可执行语句中的自由变量可用,当我们在上面调用 f() 时会发生这种情况,但当我们使用 exec() 时不会发生这种情况.这可以通过以下更容易地显示 -

my_code = """A类(对象):经过打印 'locals in body: %s' % locals()打印 'A: %s' % A定义 f():打印 'A in f: %s' % AF()B类(对象):a_ref = A"""

哪个输出

局部变量:{'A': }A:<A"类>回溯(最近一次调用最后一次): 中的文件python_test.py",第 20 行exec(my_code_AST, global_env, local_env)文件我的代码",第 11 行,在 <module> 中.文件我的代码",第 9 行,在 f 中NameError:未定义全局名称A"

所以我想新的问题是——为什么那些本地变量没有在函数和类定义中作为自由变量公开——这似乎是一个非常标准的闭包场景.

解决方案

嗯,我相信这要么是一个实现错误,要么是一个未记录的设计决定.问题的关键是模块范围中的名称绑定操作应该绑定到全局变量.它的实现方式是,当在模块级别时, globals() 是 locals() (在解释器中尝试那个),因此当您进行任何名称绑定时,它会像往常一样将其分配给 locals() 字典,它也是全局变量,因此创建了一个全局变量.

查找变量时,首先检查当前的局部变量,如果找不到名称,则递归地检查变量名称的包含范围的局部变量,直到找到变量或到达模块范围.如果达到该值,则检查全局变量,它们应该是模块范围的局部变量.

<预><代码>>>>exec(compile("import sys\nprint sys._getframe().f_code.co_name", "blah", "exec"), {}, {})<模块>>>>exec("a = 1\nclass A(object):\n\tprint a\n", {}, {})回溯(最近一次调用最后一次):文件<stdin>",第 1 行,在 <module> 中文件<string>",第 2 行,在 <module>文件",第 3 行,在 A 中NameError: 名称 'a' 未定义>>>d = {}>>>exec("a = 1\nclass A(object):\n\tprint a\n", d,d)1

这种行为就是继承起作用的原因(名称查找使用代码对象的范围 locals(),其中确实包含 A).

最后,这是 CPython 实现中的一个丑陋的 hack,特殊外壳全局查找.它还会导致一些荒谬的人为情况 - 例如:

<预><代码>>>>定义 f():... 全球 a... a = 1...>>>F()>>>'a' 在 locals()真的

请注意,这是我在阅读 python 语言参考的第 4.1 节(命名和绑定)时对解释器进行混淆的所有推断.虽然这不是确定的(我还没有打开 CPython 的源代码),但我很确定我对这种行为是正确的.

I'm trying to run a piece of python code using exec.

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

which results in the following output

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

However, if I change the code to this -

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

then it works fine - giving the following output -

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

Clearly A is present and accessible - what's going wrong in the first piece of code? I'm using 2.6.5, cheers,

Colin

* UPDATE 1 *

If I check the locals() inside the class -

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

Then it becomes clear that locals() is not the same in both places -

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

However, if I do this, there is no problem -

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

  class B(object):
    a_ref = A

f()

print 'Finished OK'

* UPDATE 2 *

ok, so the docs here - http://docs.python.org/reference/executionmodel.html

'A class definition is an executable statement that may use and define names. These references follow the normal rules for name resolution. The namespace of the class definition becomes the attribute dictionary of the class. Names defined at the class scope are not visible in methods.'

It seems to me that 'A' should be made available as a free variable within the executable statement that is the definition of B, and this happens when we call f() above, but not when we use exec(). This can be more easily shown with the following -

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
"""

which outputs

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

So I guess the new question is - why aren't those locals being exposed as free variables in functions and class definitions - it seems like a pretty standard closure scenario.

解决方案

Well, I believe it's either an implementation bug or an undocumented design decision. The crux of the issue is that a name-binding operation in the module-scope should bind to a global variable. The way it is achieved is that when in the module level, globals() IS locals() (try that one out in the interpreter), so when you do any name-binding, it assigns it, as usual, to the locals() dictionary, which is also the globals, hence a global variable is created.

When you look up a variable, you first check your current locals, and if the name is not found, you recursively check locals of containing scopes for the variable name until you find the variable or reach the module-scope. If you reach that, you check the globals, which are supposed to be the module scope's 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

This behavior is why inheritance worked (The name-lookup used code object's scope locals(), which indeed had A in it).

In the end, it's an ugly hack in the CPython implementation, special-casing globals lookup. It also causes some nonsensical artifical situations - e.g.:

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

Please note that this is all my inference based on messing with the interpreter while reading section 4.1 (Naming and binding) of the python language reference. While this isn't definitive (I haven't opened CPython's sources), I'm fairly sure I'm correct about the behavior.

这篇关于python exec() 中的全局变量和局部变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆