Python LEGB (Local, Enclosing, Global, Build in) 規則
阿新 • • 發佈:2017-09-12
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 1819 例子的輸出結果是 ‘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) 規則