2016-08-05 57 views
2

我想了解變量是如何由Python內部管理的。Python無法訪問變量分配導致UnboundLocalError

x = 10 
def ex1(): 
    if False: 
     x=1 
    print(x) 
ex1() 

當執行EX1(),它示出了UnboundLocalError因爲局部變量 'x' 的未被引用。

這是怎麼發生的? 解析是否發生在初始傳遞中,只是創建符號表並指定範圍,然後在另一個傳遞中發生解釋,並跳過x=1,因爲它是不可訪問的?

+0

這是正確的。 –

回答

0

Python沒有變量聲明,所以當創建/使用變量時,它必須確定範圍本身。 Python範圍是詞法,意味着它可以訪問其封閉範圍內的變量,但不能修改它們。 寫入ex1()的方式,x = 1對於ex1()是本地的。但是,當您運行ex1()時,它會嘗試讀取x = 10,因爲它是本地的,並引發您的UnboundLocalError。 因此,該變量的管理方式,它看到一個本地聲明,運行該函數,並看到另一個本地聲明,由於範圍,不能涉及兩者。

0

從概念上講,這是有道理的。我不知道它是如何實施的,但我可以說明原因。

當您影響變量時,它會受到本地範圍的影響,除非您使用關鍵字global明確告知。如果你只訪問它並且沒有任何作用,它將隱含地使用全局變量,因爲沒有定義局部變量。

x = 10 

def access_global(): 
    print x 

def affect_local(): 
    x = 0 
    print x 

def affect_global(): 
    global x 
    x = 1 
    print x 

access_global() # 10 
affect_local() # 0 
print x   # 10 
affect_global() # 1 
print x   # 10 

如果你這樣做的嵌套函數,類或模塊內部的規則類似:

def main(): 
    y = 10 
    def access(): 
     print y 
    def affect(): 
     y = 0 
     print y 

    access() # 10 
    affect() # 0 
    print y # 10 

main() 

這是由父作用域從來沒有覆蓋變量可能節省痛苦的調試的時間,除非其明確說明。

編輯

拆卸巨蟒字節代碼爲我們提供了一些額外的信息來了解:

import dis 
x = 10 
def local(): 
    if False: 
     x = 1 

def global_(): 
    global x 
    x = 1 

print local 
dis.dis(local) 
print global_ 
dis.dis(global_) 


<function local at 0x7fa01ec6cde8> 
37   0 LOAD_GLOBAL    0 (False) 
       3 POP_JUMP_IF_FALSE  15 

38   6 LOAD_CONST    1 (1) 
       9 STORE_FAST    0 (x) 
      12 JUMP_FORWARD    0 (to 15) 
     >> 15 LOAD_CONST    0 (None) 
      18 RETURN_VALUE   
<function global_ at 0x7fa01ec6ce60> 
42   0 LOAD_CONST    1 (1) 
       3 STORE_GLOBAL    0 (x) 
       6 LOAD_CONST    0 (None) 
       9 RETURN_VALUE  

我們可以看到,對於local功能字節代碼調用STORE_FASTglobal_函數調用STORE_GLOBAL

這個問題也解釋了爲什麼它更高性能的翻譯功能,字節碼編譯避免每次函數調用時: Why python compile the source to bytecode before interpreting?