簡體   English   中英

Python exec()函數在2.7以上的版本中損壞嗎? 錯誤:未定義“名稱”

[英]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()調用最終創建和打印變量foobar ,這是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()看到foobar ,但是代碼/解釋器卻看不到它。 更奇怪的是,這個調試腳本和解決任何變量是全成(我已經設置斷點# exception here和類型foo在調試窗口中使用VS代碼。 foo正確與“6”的值解決。

如果相同的代碼(函數func()內的東西)沒有包含在函數中,這將按預期工作,打印出foobar

知道這里發生了什么嗎?


更新:我進一步簡化了這個問題:

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

  1. 'bar':“當地的'bar'變量現在可以在def func2()里面找到。它是:一個蘇格蘭威士忌...讓我們喝酒......神秘的解決!”
  2. 'localVarToEvaluate':'foo = varValue'
  3. 'varValue':42
  4. 'foo':42
  5. 'varName':'foo'
  6. 'x':'蘇格蘭威士忌...讓我們喝..霧氣解決了!'
  7. 'func2':“<”函數func2位於0x000002B070027F28“>”#without“outside”>“。

在子彈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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM