Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/365.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
python exec()中的全局变量和局部变量_Python_Scope - Fatal编程技术网

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

python exec()中的全局变量和局部变量,python,scope,Python,Scope,我正在尝试使用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, globa

我正在尝试使用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
然后它工作良好-提供以下输出-

locals: {'A': <class 'A'>}
A: <class 'A'>
{'A': <class 'A'>, 'B': <class 'B'>}
然后很明显,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
*更新2*

好的,这里的文档-

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

在我看来,“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
主体中的局部变量:{'A':}
A:
回溯(最近一次呼叫最后一次):
文件“python_test.py”,第20行,在
执行官(我的代码、全局环境、本地环境)
文件“我的代码”,第11行,在
文件“我的代码”,第9行,在f中
NameError:未定义全局名称“A”

因此,我想新的问题是——为什么这些局部变量没有在函数和类定义中作为自由变量公开——这似乎是一个相当标准的闭包场景。

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

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

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

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

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

exec code in dict()
print locals()
globals()
之后,您将找到exec抛出“not defined”异常的原因,您可以试试这个

d = dict(locals(), **globals())
exec (code, d, d)
印刷品

global_env.keys() = ['__builtins__', 'A', 'B']
B.a = <class 'A'>
global_env.keys()
B.a=
霍克特,你说

我希望使用这样的局部变量的主要原因是获取代码字符串中定义的所有内容,而不需要python在全局变量中放入的所有其他内容

使用exec,如果您的全局变量没有定义
\uuuuuuuuuuuuuuuuuuuuuu
,exec会向全局变量添加一个项目
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
,这样您就可以得到A、B和
<代码>\uuuu内置\uuuuu
本身就是一个大字典,但它总是要删除的同一个元素(只要在删除之前等待代码使用完毕!)。记录在exec()下

评估的文件在说

如果全局字典存在并且缺少“内置项”,则在解析表达式之前,将当前全局复制到全局

但实际上,它似乎只是在中复制
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu内置的


(注意:其他人都说:要么将全局变量和局部变量设置为相同的值,要么在全局环境中说
exec my_code\u AST
,而不使用单独的局部环境。)

这似乎和这个问题是同一个问题:感谢指针-我不是python大师,但当我打印局部变量()时,A已经被编译成一个局部变量——也就是说,它确实知道如何处理它。您突出显示的问题的答案是-“编译无法知道a是一个freevar,因此它将其编译为一个全局引用”。这里的问题似乎是,在使用exec时,局部变量()在B的主体内被重新定义,但在使用函数时却不被重新定义(请参阅相关更新)?这很可能是我对这个答案的误解……我在这个问题上添加了第二个更新,澄清了一些事情——至少是发生了什么,但仍然没有解释为什么。好吧——谢谢你提供的信息——这很麻烦:)我想这样使用当地人的主要原因,就是获取代码字符串中定义的所有内容,而不包含python放入全局的所有其他内容。如果我在代码中“print globals()”,这是一个很大的东西字典,这是有意义的,但现在我不知道如何将代码字符串中定义的东西放入字典中,即只包含{'a','B',}的字典。我不想手动删除所有内容,我也不知道代码字符串中的内容。我将标记这个问题的答案-我在这里提交了一个python错误-干杯。我提交的错误是重复的。我已经在2.6+版本中对此进行了讨论-看起来这是一个“无法修复”的问题。我认为execapi具有很强的误导性,默认值很差。我推荐。更好的是,这是您可以发送和接收全球/本地邮件的唯一响应。回答得很好。然后可以使用d作为从子代码访问变量的基础。如果代码中的status={},则为d['status']。谢谢你@Zoe
>>> def f():
...     global a
...     a = 1
...
>>> f()
>>> 'a' in locals()
True
exec code in dict()
d = dict(locals(), **globals())
exec (code, d, d)
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'>