1. 程式人生 > >Python LEGB (Local, Enclosing, Global, Build in) 規則

Python LEGB (Local, Enclosing, Global, Build in) 規則

logs nco 理解 意圖 exc 整體 概念 首字母 error:

 1       
       Local 一個函數定義了一個 local 作用域; PyFrameObject 中的 f_local 屬性 2 Global 一個 module 定義了一個 global 作用域; PyFrameObject 中的 f_global 屬性. 3 BuiltIn open, dir 的作用域等等, python 最頂層的作用域
4 Enclosing 5 例子, 6 b = 2 7 def funcO():
8 b = 3 9 def funcI(): 10 print(b) 11 return funcI 12 13 f = funcO() 14 f() #1 15 16 Output, 17 3 #1 18
19 例子的輸出結果是 3 而不是代碼塊兒最外層所定義的 b = 2. 20 f() 實際調用的內嵌在 funcO 中的 funcI 函數. funcI 位於 funcO 之內, 所以函數 funcI 的作用域內嵌於函數 funcO 的作用域內. 21 即, 函數 funcO 的作用域是內嵌函數 funcI 的直接外圍作用域, 所以例子的結果是 3 而不是 2. 22 單純按照代碼塊兒的結構來說, 在 #1 處 ‘b = 3‘ 這個約束已經不再對 ‘f()‘ 這個調用起作用, 但是從打印的結果來看顯然不是這樣(依然起作用).
23 Python 虛擬機在執行 f = funcO() 的時候會執行 def funcI(): (因為 函數 funcO return 了 funcI 函數對象), 24 就在這個時候 約束b = 3 與函數對象 funcI 捆綁了一起, 並把捆綁後的街哦過返回, 這個捆綁起來的整體被稱為 閉包(捆綁 一詞可以理解為 直接外圍作用域 的綁定過程). 25 閉包是 LEGB 規則中的 E -> enclosing 的首字母, 表示的是 直接外圍作用域 這個概念. 26 27 global 關鍵字, 28 例子, 29 c = 1 30 def func1(): 31 print(c) 32 33 def func2(): 34 print(c) 35 c = 3 36 print(c) 37 38 func1() 39 func2() 40 41 Output, 42 1 # func1() 的打印 43 func2() # func2() 的打印 44 print(c) 45 UnboundLocalError: local variable c referenced before assignment 46 47 func1 和 func2 同是對直接外圍作用域的搜索, 為什麽一個正確搜索約束 c = 1,另一報錯呢? 48 先來了解一個名字的定義 - 最內嵌套作用域規則. 49 最內嵌套作用域規則:由一個賦值語句引進的名字在這個賦值語句所在的作用域裏是可見(起作用)的, 50 而且在其內部嵌套的每個作用域裏也可見,除非它被嵌套於內部的, 51 引進同樣名字的另一條賦值語句所遮蔽/覆蓋。 52 53 從 exception 中得知, 變量 c 沒有被定義. 上述問題就出現在定義的後半句,‘除非’分句 - 除非它被嵌套於內部的, 54 引進同樣名字的另一條賦值語句所遮蔽/覆蓋。 恰巧緊接著報錯處, 通過賦值語句引進了一個同名約束(c = 3),進而破壞了最內嵌套作用域規則. 55 56 現在嘗試修改這個引用錯誤, 57 c = 1 58 def func1(): 59 print(c) #1 60 61 def func2(): 62 global c #2 在引用之前通過 global 關鍵字指定作用域 63 print(c) #2 64 c = 3 65 print(c) #3 66 67 func1() 68 func2() 69 print(c) #4 70 71 Output, 72 1 #1 73 1 #2 python 理解了編程者的意圖 74 3 #3 75 3 #4 76 進一步再看一個閉包的例子, 77 d = 1 78 def func2(): 79 d = 3 80 def func2I(): 81 global d 82 print(d) #1 83 d += 4 #2 重寫直接外層作用域 84 print(d) #2 85 return func2I 86 87 abc = func2() 88 abc() 89 print(d) #3 90 91 Output, 92 1 #1 global 關鍵字 打破 LEGB 規則, 限定引用直接外層作用於 93 5 #2 直接外層作用於被重寫 94 5 #3 被重寫的‘直接外作用域’(代碼塊兒最外層的 ‘d = 1‘ 這個約束)作用於 LEGB 規則下作用域

Python LEGB (Local, Enclosing, Global, Build in) 規則