python3 中關於global和nonloal的作用域
安利一波這位大佬的部落格安利寫的真的不錯,就是有點長基本看完就懂了,我這裡給出自己的理解,外加一些大佬沒有給出的測試情況。
一:global是標記此變數是全域性變數
例如如下的程式
b = 12
def get():
return b
print(get())
12
上面段程式碼執行完全沒有問題,但是下面這段:
b = 12
def get():
b = b + 2
return b
print(get()
就會報錯。這是因為python3裡面對全域性變數只能引用不能修改,如果修改需要加上global宣告。將上面這段程式碼改一下一下就可以得到正確的結果
b = 12
def get():
global b
b = b + 2
return b
print(get())
14
其實還有一個比較有趣的現象.如果函式外面沒有宣告變數,直接在函式裡面用global宣告一個變數,當呼叫了這個函式後,在外面也可以用這個變量了。
def get():
global b
b = 4
b = b + 2
return b
print(get())
print(b)
6
6
還有一個讓我覺得有趣的現象:
L = [1, 2]
def get():
L.append(3)
return L
print(get())
print(L)
[1 , 2, 3]
[1, 2, 3]
以上這段程式碼沒有用global宣告,貌似好像也能’修改’函式外面的變數?
其實本質上說get()函式並沒有修改L,對於list這類可變變數來說,對其刪除和新增元素並不能算是修改該變數。,對於L來說其指向的物件並沒有改變,只是物件本身變了而已。舉個例子,這就像在呼叫get函式之前我找的是小明同學,在呼叫get()函式後,我找的是多穿了一件衣服的小明同學。
L = [1, 2]
def get():
L = 2
return L
print(get())
print(L)
2
[1, 2]
這段程式碼並沒有報錯,因為get()函式內部的L看成了初始化了一個區域性變數的操作,而全域性的L並沒有改變。
L = [1, 2]
def get():
global L
L = 2
return L
print(get())
print(L)
2
2
以上程式碼就會修改外部的全域性變數。
二:nonlocalb宣告的變數,會從當前作用域的外層(該外層不能包括全域性變數)尋找該變數。
b = 1
def get():
nonlocal b
b = b+10
return b
print(get())
print(b)
SyntaxError: no binding for nonlocal 'b' found
以上程式碼會報錯,這個就是(該外層不包括全域性)的意思。
b = 10
def get():
b = 20
def f():
b = b + 1
return b
print(f())
return b
print(get())
print(b)
UnboundLocalError: local variable 'b' referenced before assignment
這段程式碼會報錯,但是如果在f函式內部加上nonlocal宣告的話,就可以正常運行了輸出是:21 21 10
如果把f函式內的加上global申明的話,輸出就會變成:11 20 11。可以看出雖然變數名字一樣,但只要加上global宣告就會和最外層的全域性變數繫結
b = 10
def get():
b = 20
def f():
b = 11
def w():
nonlocal b
b = -1
return b
print('w -> %d' % w())
return b
print('f -> %d' % f())
return b
print('get -> %d' % get())
print('b -> %d' % b)
w -> -1
f -> -1
get -> 20
b -> 10
上面這個函式和輸出結果說明,nonlocal會繫結和當前作用域最近的那個變數。
b = 10
def get():
b = 20
def f():
def w():
nonlocal b
b = -1
return b
print('w -> %d' % w())
return None
f()
return b
print('get -> %d' % get())
print('b -> %d' % b)
w -> -1
get -> -1
b -> 10
這裡發現即使相隔兩層,但是仍然可以繫結到所需要的變數。
b = 10
def get():
def g():
b = 1
return 1
def f():
nonlocal b
b = 20
return b
print('g -> %d' % g())
print('f -> %d' % f())
return b
print('get -> %d' % get())
print('b -> %d' % b)
SyntaxError: no binding for nonlocal 'b' found
上面這段程式碼會報錯,這個說明,對於並行的兩個函式的變數,無法相互繫結。只有包含關係才可以。