2010-02-09 64 views
3

我有一點很難理解什麼是用下面的函數腳麻:Python的瓦爾()全局名稱錯誤

def ness(): 
pie='yum' 
vars()[pie]=4 
print vars()[pie] 
print yum 

所以,當我跑,我得到這樣的結果:

>>> ness() 
4 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 5, in ness 
NameError: global name 'yum' is not defined 

如果我不把它寫成一個函數,只需鍵入它在命令行上一次在一個行,它工作正常,像這樣:

>>> pie='yum' 
>>> vars()[pie]=4 
>>> print vars()[pie] 
4 
>>> print yum 
4 
>>> 

編輯: 假設我想使事情比這更復雜,而不是百勝設定的值並打印該值,我定義了一些功能,並希望基於一些輸入調用其中的一個:

def ness(choo): 
    dic={} 
    dessert=() 
    dnum=[10,100] 
    desserts='pie' 
    dic[dessert]=str(desserts[bisect(dnum,choo)]) 
    vars()[dic[dessert]]() 
def p(): 
    print 'ummmm ummm' 
def i(): 
    print 'hooo aaaaa' 
def e(): 
    print 'woooo' 

所以,當我打電話內斯我得到一個關鍵的錯誤:

>>> ness(3) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 7, in ness 
KeyError: 'p' 

現在我知道我可以做這樣的事情了一些ELIF語句,但我不知道這是否會工作太時,如果使用開張像這樣會比使用elifs更高效(比如說,如果我需要檢查1000個choo值)。

非常感謝您的幫助。

回答

2

有辦法以exec做

>>> def ness(): 
... pie='yum' 
... exec pie+"=4" 
... print vars()[pie] 
... print yum 
... 
>>> 
>>> ness() 
4 
4 

而是做着的是,採用了全新的字典是更好的安全

>>> def ness(): 
... dic={} 
... pie='yum' 
... dic[pie]=4 
... print dic[pie] 
... print dic['yum'] 
... 
>>> ness() 
4 
4 
>>> 
+0

使用exec做了上面寫的更復雜的例子的竅門(沒有像我們試圖給我們的關鍵錯誤電子詞典以及變量。究竟使用dict比exec更安全?是什麼gnibbler說: 「返回的字典不應該被修改:對相應的符號表的影響是不明確的」 這意味着使用exec這種方式可能會導致不可預見的問題? – Jamie 2010-02-09 15:17:12

+0

exec可以執行任何python代碼,例如'exec「os.system('reboot_your_pc')」,所以最好避免使用它。 – YOU 2010-02-09 15:49:42

+0

另外exec可以給你一個令人困惑的stacktrace,並且比明確的字典要慢得多(它必須從頭開始解析)。 – viraptor 2010-02-28 17:50:13

1

這是not safe修改()由瓦爾返回的字典

vars([object])¶

Without an argument, act like locals().

With a module, class or class instance object as argument (or anything else that has a dict attribute), return that attribute.

Note

The returned dictionary should not be modified: the effects on the corresponding symbol table are undefined.

你的第二個例子是一個特例。 vars()相當於globals()在全局命名空間,並通過globals()返回的字典表現爲你所期望的(但是是不可取的)

>>> id(vars()),id(globals()) 
(3085426868L, 3085426868L) 
4

vars()函數內給你當地的命名空間,就像locals() - 見the docs。功能之外(例如在提示時)locals()(當然還有vars())爲您提供模塊的全局命名空間,就像globals()一樣。正如the docs所說,在Python中不支持通過locals()(或等效地,在函數內部的vars())嘗試分配給函數的局部變量。如果你想分配給全球變量,你當你做在提示符下(或以其他方式功能之外),使用globals()代替vars()(也許不是最乾淨的方法 - 全局變量應是可以理解皺起眉頭 - 但它確實有效)。

0

vars()相當於locals(),該函數在其範圍內是局部變量,在交互式解釋程序中是vars() is globals()locals()僅供閱讀;試圖改變它的效果是不確定的(實際上,它不起作用)。 globals()可以進行修改,但你仍然應該從未直接放任何東西在它返回的字典。

0

[編輯:我一定是錯的,因爲'exec'的例子有效。]

正如大家指出的那樣,修改vars()是一個壞主意。但是,通過認識到python在某種意義上不會「看到」「yum」是本地的,你可以理解錯誤。 「print yum」仍然是作爲全球參考解決的;這發生在任何代碼執行之前。

這是你從得到一個UnboundLocalError同樣的原因:

>>> y = 100 
>>> def foo(x): 
... if x == 1: 
...  y = 10 
... print y 
... 
>>> foo(1) 
10 
>>> foo(2) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 4, in foo 
UnboundLocalError: local variable 'y' referenced before assignment 
相關問題