[英]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_env
說exec my_code_AST in global_env
而無需單獨的local_env。)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.