[英]Python globals, locals, and UnboundLocalError
我最近遇到了UnboundLocalError
這個案例,這看起來很奇怪:
import pprint
def main():
if 'pprint' in globals(): print 'pprint is in globals()'
pprint.pprint('Spam')
from pprint import pprint
pprint('Eggs')
if __name__ == '__main__': main()
哪個產生:
pprint is in globals()
Traceback (most recent call last):
File "weird.py", line 9, in <module>
if __name__ == '__main__': main()
File "weird.py", line 5, in main
pprint.pprint('Spam')
UnboundLocalError: local variable 'pprint' referenced before assignment
pprint
明確地綁定在globals
,並且將在以下語句中綁定到locals
globals
。 有人可以解釋一下為什么它不樂意解決pprint
到globals
的綁定嗎?
編輯:由於回復良好,我可以用相關術語澄清我的問題:
在編譯時,標識符pprint
被標記為幀的本地。 執行模型是否區分本地標識符綁定在框架內的哪個位置 ? 它可以說,“引用全局綁定直到這個字節碼指令,此時它已經反彈到本地綁定”,或者執行模型沒有考慮到這一點?
哪里出乎意料? 您在該范圍內重新分配的范圍的任何全局變量都由編譯器標記為該范圍的本地。
如果進口的處理方式不同, 那將是令人驚訝的。
但是,可以在不在其中使用符號之后命名模塊,反之亦然。
好吧,這對我來說很有趣,我可以通過http://docs.python.org/reference/executionmodel.html閱讀。
然后在這里和那里做了一些修補你的代碼,這是我能找到的:
碼:
import pprint
def two():
from pprint import pprint
print globals()['pprint']
pprint('Eggs')
print globals()['pprint']
def main():
if 'pprint' in globals():
print 'pprint is in globals()'
global pprint
print globals()['pprint']
pprint.pprint('Spam')
from pprint import pprint
print globals()['pprint']
pprint('Eggs')
def three():
print globals()['pprint']
pprint.pprint('Spam')
if __name__ == '__main__':
two()
print('\n')
three()
print('\n')
main()
輸出:
<module 'pprint' from '/usr/lib/python2.5/pprint.pyc'>
'Eggs'
<module 'pprint' from '/usr/lib/python2.5/pprint.pyc'>
<module 'pprint' from '/usr/lib/python2.5/pprint.pyc'>
'Spam'
pprint is in globals()
<module 'pprint' from '/usr/lib/python2.5/pprint.pyc'>
'Spam'
<function pprint at 0xb7d596f4>
'Eggs'
在from pprint import pprint
的方法two()
from pprint import pprint
但是沒有覆蓋globals
的名稱pprint
,因為global
關鍵字不在 two()
的范圍內使用。
在方法three()
因為在本地范圍內沒有pprint
名稱的聲明, pprint
它默認為全局名稱pprint
,這是一個模塊
而在main()
,首先使用關鍵字global
,因此在方法main()
范圍內對pprint
所有引用都將引用global
名稱pprint
。 我們可以看到最初是一個模塊,並在global
namespace
使用方法覆蓋,因為我們from pprint import pprint
執行此from pprint import pprint
雖然這可能沒有回答這個問題,但我認為這是一個有趣的事實。
=====================
編輯另一件有趣的事。
如果你有一個模塊說:
mod1
from datetime import datetime
def foo():
print "bar"
另一種方法說:
mod2
import datetime
from mod1 import *
if __name__ == '__main__':
print datetime.datetime.now()
乍一看似乎是正確的,因為你已經在mod2
導入了模塊datetime
時間。
現在,如果您嘗試將mod2作為腳本運行,則會拋出錯誤:
Traceback (most recent call last):
File "mod2.py", line 5, in <module>
print datetime.datetime.now()
AttributeError: type object 'datetime.datetime' has no attribute 'datetime'
因為from mod2 import *
的第二次導入覆蓋了命名空間中的名稱datetime
,因此第一個import datetime
時間不再有效。
道德:因此,進口的順序,進口的性質(來自x進口*)和進口模塊中的進口意識 - 很重要 。
幾周前這個問題得到了回答,但我想我可以澄清一下這些答案。 首先是一些事實。
1:在Python中,
import foo
幾乎完全一樣
foo = __import__("foo", globals(), locals(), [], -1)
2:在函數中執行代碼時,如果Python遇到尚未在函數中定義的變量,它將在全局范圍內查找。
3:Python有一個用於稱為“本地”的函數的優化。 當Python對函數進行標記時,它會跟蹤您分配給的所有變量。 它為每個變量分配一個來自本地單調遞增整數的數字。 當Python運行該函數時,它會創建一個包含與局部變量一樣多的插槽的數組,並為每個插槽分配一個特殊值,表示“尚未分配給尚未”,這就是存儲這些變量的值的位置。 如果引用尚未分配的本地,Python會看到該特殊值並拋出UnboundLocalValue異常。
舞台現已確定。 你的“來自pprint import pprint”實際上是一種任務形式。 所以Python創建了一個名為“pprint”的局部變量,它封閉了全局變量。 然后,當你在函數中引用“pprint.pprint”時,你會遇到特殊值,Python會拋出異常。 如果你在函數中沒有import語句,那么Python將使用普通的look-in-locals-first-then-look-in-globals解析並在globals中找到pprint模塊。
要消除歧義,您可以使用“global”關鍵字。 當然,現在你已經解決了你的問題,我不知道你是否真的需要“全球”或者是否需要其他方法。
看起來像Python中看到from pprint import pprint
線和標志pprint
當地的名main()
執行任何代碼之前 。 由於Python認為pprint應該是一個局部變量,在使用from..import
語句“賦值”之前用pprint.pprint()
引用它,它會拋出該錯誤。
這就像我能做到的那樣有意義。
當然,道德是將這些import
聲明放在最重要的范圍內。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.