[英]Python exec() function broken in versions above 2.7? Error: 'name' not defined
我發現了python exec()
函數的異常行為。 這是代碼:
variables = {
('foo', 6),
('bar', 42)
}
def func():
for varData in variables:
varName, varValue = varData
localVarToEvaluate = varName + ' = varValue'
try:
#exec(localVarToEvaluate, globals(), locals())
exec(localVarToEvaluate)
except Exception as err:
print(str(err))
if varName not in locals():
print("Variable names '", varName, "can't be found in local scope!")
if 'foo' in locals():
print("'foo' OK:", foo) # exception here
else:
print("'foo' not available!")
if 'bar' in locals():
print("'bar' OK:", bar)
else:
print("'bar' not available!")
func()
我希望通過exec()
調用最終創建和打印變量foo
和bar
,這是Python 2.7的情況。 以上所有內容(在3.3,3.4,3.6和3.7上測試)拋出異常, foo
未定義:
Exception has occurred: NameError
name 'foo' is not defined
奇怪的是,通過運行locals()
, globals()
或dir()
(也可以通過if
語句確認locals()
看到foo
和bar
,但是代碼/解釋器卻看不到它。 更奇怪的是,這個調試腳本和解決任何變量是全成(我已經設置斷點# exception here
和類型foo
在調試窗口中使用VS代碼。 foo
正確與“6”的值解決。
如果相同的代碼(函數func()
內的東西)沒有包含在函數中,這將按預期工作,打印出foo
和bar
。
知道這里發生了什么嗎?
更新:我進一步簡化了這個問題:
# take 1, create local variable 'foo' with value 6. Not in function.
varName = 'foo'
varValue = 42
localVarToEvaluate = varName + ' = varValue'
try:
exec(localVarToEvaluate)
except Exception as err:
print(str(err))
if 'foo' in locals():
# print(locals()['foo']) # (1)
# print(foo) # (2)
print("'foo' OK:", foo) # (3)
# take 2, create local variable 'bar' with value 42
def func2():
varName = 'bar'
varValue = 42
localVarToEvaluate = varName + ' = varValue'
try:
exec(localVarToEvaluate)
except Exception as err:
print(str(err))
if 'bar' in locals():
# print(locals()['bar']) # (1)
# print(bar) # (2)
#print("'bar' OK:", bar) # (3)
pass # uncomment any line above
func2()
當此代碼執行時,首先:
'foo' OK: 6
是打印,而不是引發此異常:
Exception has occurred: NameError
name 'bar' is not defined
...
請注意,這兩個代碼是相同的,只是在函數func2()
創建了“ bar”變量。
我感興趣的不是解決方法,而是解釋,為什么這樣做以及為什么點(1)有效,而(2)和(3)沒有。 請注意, bar
變量在locals()
可見,而通過直接調用它無法訪問 - 但只有在函數內部創建它!
OP解決了很多關於這個問題的不明確問題。 查看答案編輯。 它歸結為(導入)掛鈎本地(變量,defs,類),以便它們可以在定義中使用。
請參閱下面的答案以及內嵌注釋,這是什么,為什么。
# take 1, create local variable 'foo' with value 6. Not in function.
# >>> code is executed in local-scope <<<
varName = 'foo'
varValue = 42
localVarToEvaluate = varName + ' = varValue'
try:
exec(localVarToEvaluate) # (0) dict item becomes {varName : varValue}
print (localVarToEvaluate) # (1) prints > foo = varValue < dict item
except Exception as err:
print(str(err))
if 'foo' in locals():
print(locals()['foo']) # (2) prints > 42 < value
print(foo) # (3) prints > 42 < value
print("'foo' OK:", foo) # (4) prints > 'foo' OK: 42 < stringtext, value
# take 2, create local variable 'bar' with value 42
def func2(self):
# >>> code executed inside function and not local-scope <<<
varName = 'bar'
varValue = 42
localVar2Evaluate = varName + ' = varValue'
try:
exec(localVar2Evaluate) # (5) dict item becomes {varName : varValue}
print (localVar2Evaluate) # (6) prints > bar = varValue < dict item
except Exception as err:
print(str(err))
print ('local-scope :', '\n', locals()) # (7) {'bar': 42, 'localVar2Evaluate': 'bar = varValue', 'varValue': 42, 'varName': 'bar'}
if 'bar' in locals():
print(locals()['bar']) # (1)
print(bar) # (2) < --- python is not looking here in the locals() but inside the def for variable `bar` which is not made unless you give it access (hook or reference) via e.g. self.
print("'bar' OK:", bar) # (3)
# pass # uncomment any line above
x = 'a scotch... lets drink.. mystery solved!'
bar = "the local 'bar' variable is now available inside def func2().. It is: %s" % x
func2(bar)
如您所見,我(導入)使用varName'bar'創建了一個到局部變量的鈎子,該鈎子將在self
的定義中使用。 它可以是任何名稱TBH查看pydocs self
等
結果:
bar = varValue
local-scope :
{'localVar2Evaluate': 'bar = varValue', 'varValue': 42, 'bar': 42, 'self': "the local 'bar' variable is now available inside def func2().. It is: a scotch... lets drink.. mystery solved!", 'varName': 'bar'}
42
the local 'bar' variable is now available inside def func2().. It is: a scotch... lets drink.. mystery solved!
'bar' OK: the local 'bar' variable is now available inside def func2().. It is: a scotch... lets drink.. mystery solved!
如果在func()下面print('\\n\\n', locals())
,則會得到以下printresult:
在子彈7,你看到func2鏈接。
更新4:
在python 2.7.16和3.5.2之間切換顯示localals()dict和globals()dict中的ONE更改沒有變化,如下所示。
在2.7版中: 'variables': set([('bar', 42), ('foo', 6)])
3.5: 'variables': {('bar', 42), ('foo', 6)}
...這個set()
在我看來不再起作用,是您在3.5中解決的原因。
我通過調整你的腳本來測試它:
import sys
print (sys.version)
variables = {('foo', 6), ('bar', 42)}
def func():
for varData in variables:
varName, varValue = varData
localVarToEvaluate = varName + ' = varValue'
try:
exec(localVarToEvaluate)
print ('t2\n', locals())
except Exception as err:
print(str(err))
if varName not in globals():
print("Variable names '", varName, "can't be found in global scope!")
if 'foo' in globals():
print("'foo' OK:", foo) # exception here
else:
print("'foo' not available!")
if 'bar' in globals():
print("'bar' OK:", bar)
else:
print("'bar' not available!")
print ('t1\n', globals())
func()
然后......它仍然可以是執行官。 所以我禁用了運行func()
並且globals()
的差異仍然存在。 所以我認為這與globals()
函數(而不是exec
globals()
有所不同。
我已經報告了Python Issue Tracker的一個錯誤 , 官方的答案是:
這是目前的設計,這意味着3.8可能是它可以改變的唯一可行的地方。 它也不是特定於Windows的,因此我刪除了該組件(人們可能會將自己從愛管閑事中刪除)。
...
目前它基本上是一個只讀代理,因為本地人在功能內進行了優化,這就是為什么你無法通過風管看到更新。
底線,以這種方式使用的exec()
在函數內部是無用的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.