LEGB的名字取自:
- Locals :當(dāng)前命名空間歼捏,如函數(shù)或模塊
- Enclosing :外部嵌套函數(shù)的命名空間(閉包常見)
- Globals:全局變量的命名空間
- Builtins : 內(nèi)建模塊的命名空間
各作用域首字母
LEGB規(guī)則是:Python 使用 LEGB 的順序來查找一個(gè)符號對應(yīng)的對象
順序是:
locals -> enclosing function -> globals -> builtins
查找順序從左到右,不會反過來员凝,比如一個(gè)功能在globals迈嘹,當(dāng)它在當(dāng)前作用域找不到定義時(shí)蚕礼,只能從builtins查找叶圃,而不會從enclosing中去查找
下面以一道題來演示
def proc1():
j, k = 3, 4
print('j == %d and k == %d' % (j, k))
k = 5
def proc2():
j = 6
proc1()
print('j == %d and k == %d' % (j, k))
k = 7
proc1() #1
#print('j == %d and k == %d' % (j, k)) #2
j = 8
proc2() # 3
print('j == %d and k == %d' % (j, k)) # 4
從代碼中那個(gè)我們可以看出宴抚,一共有 #1和#3兩個(gè)函數(shù)調(diào)用勒魔,#2和#4兩個(gè)print語句(下面會說#2為何要注釋掉)
在看以下分析前,你可以自己先想下答案是什么
-
#1
Python函數(shù)從上往下運(yùn)行語句菇曲,proc1中print了 j 和 k 冠绢,print前定義了 j, k = 3, 4,因此 #1 的結(jié)果輸出是
j == 3 and k == 4
-
#2
現(xiàn)在我們來說為何#2要被注釋掉了常潮,在#2 print語句之前弟胀,只定義了k的值,而沒有定義 j 的值喊式。如果不注釋掉會報(bào)錯(cuò)
NameError: name 'j' is not defined
有人估計(jì)會問孵户,#1 中不是定義了 j 的值嗎?
因?yàn)閜roc1函數(shù)中的 j岔留、k 值只作用在 Locals 中夏哭,而 #2 中的 j、k 明顯是 Globals 中參數(shù)献联,Globals 是不會從 Locals 去搜尋值的竖配,只能從 builtins 中去尋找,所以“ j is not defined ”里逆。
-
#3
這里值得注意的是进胯, proc2 中先是 定義了 j 值,然后調(diào)用了 proc1()运悲,再 print 語句龄减,所以這里會有2個(gè)輸出
前面說,Python函數(shù)從上往下運(yùn)行語句班眯,那么 proc2 中 proc1 中的 j 值會變成 6 嗎希停?
這里雖然 j 是 proc2 的Locals參數(shù)烁巫,但 proc1 中有自己的Locals,為何要從 proc2 中去 “借”呢宠能?(如果proc1 從 proc2 中取值亚隙,那是閉包的用法了)
所以 proc1() 的結(jié)果是:
j == 3 and k == 4
隨后的 print 結(jié)果:
j == 6 and k == 7
j 是 自己定義的,k 是 Globals 的违崇,如果這里看不懂 k 為何是7阿弃,請從頭再認(rèn)真看一遍
-
#4
這個(gè)沒什么好說的:
j == 8 and k == 7
Summary | 小結(jié)
- 尋找順序:locals -> enclosing function -> globals -> builtins
- 官大一級壓死人,事情安排找“下級”