2017-09-05 25 views
2

Google Style Guide上詞法作用域:訂單可變參考和分配的嵌套函數

嵌套Python函數可以指在包圍 函數定義的變量,但是不能分配給他們。

此規範可以在這裏看到:

def toplevel(): 
    a = 5 
    def nested(): 
     # Tries to print local variable `a`, but `a` is created locally after, 
     # so `a` is referenced before assignment. You would need `nonlocal a` 
     print(a + 2) 
     a = 7 
    nested() 
    return a 
toplevel() 
# UnboundLocalError: local variable 'a' referenced before assignment 

扭轉nested兩個語句的順序擺脫這個問題:

def toplevel(): 
    a = 5 
    def nested(): 
     # Two statements' order reversed, `a` is now locally assigned and can 
     # be referenced 
     a = 7 
     print(a + 2) 
    nested() 
    return a 
toplevel() 

我的問題是,是什麼關於Python的實現,告訴第一個函數a將在本地聲明(在print語句之後)?我的理解是,Python是逐行有效地解釋的。那麼,它不應該默認在代碼中尋找非本地a

具體地說就是,如果我是使用只是參考(不分配),

def toplevel(): 
    a = 5 
    def nested(): 
     print(a + 2) 
    nested() 
    return a 
toplevel() 

莫名其妙print語句知道要引用封閉函數定義的非本地a。但如果我在之後分配給當地的a,那麼該功能對於自己的功能來說就太聰明瞭。

回答

1

我的理解是,Python被逐行有效地解釋。

這不是正確的心智模式。

分析整個函數的主體以確定哪些名稱引用局部變量,哪些不引用。

爲了簡化你的榜樣,下面還給出了UnboundLocalError

def func(): 
    print(a) 
    a = 2 

func() 

這裏,func()編譯下面的字節碼:

2   0 LOAD_FAST    0 (a) 
       3 PRINT_ITEM 
       4 PRINT_NEWLINE 

    3   5 LOAD_CONST    1 (2) 
       8 STORE_FAST    0 (a) 
      11 LOAD_CONST    0 (None) 
      14 RETURN_VALUE 

def gunc(): 
    print(a) 

其編譯比較一下到

2   0 LOAD_GLOBAL    0 (a) 
       3 PRINT_ITEM 
       4 PRINT_NEWLINE 
       5 LOAD_CONST    0 (None) 
       8 RETURN_VALUE 

觀察a的賦值缺席情況是如何將參考文獻從局部變爲全局的。

1

我的理解是,Python是有效地線

這就是你錯了解釋線。在任何解釋開始之前,整個文件被編譯爲字節碼。

此外,即使字節碼編譯通道不存在,print(a + 2)也不會在看到a = 7之前執行,因爲它在函數定義中。到它實際嘗試執行時,Python仍然知道a = 7print(a + 2)

+0

也許OP意思是字節碼是按指令執行的,這是正確的。不是嗎? – direprobs

+0

@direprobs:它不像你想象的那麼正確,因爲函數調用(明確的或者隱含在'+'之類的東西中)通常會導致字節碼指令在其他字節碼指令的中間執行,但無論如何,我認爲提問者確實意味着逐行。 – user2357112

0

document

的Python的一個特別之處就是 - 如果沒有global聲明生效 - 分配到的名字總是進入最裏面的範圍。分配不會複製數據 - 它們只是將名稱綁定到對象。