1. 程式人生 > >python3 中關於global和nonloal的作用域

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

上面這段程式碼會報錯,這個說明,對於並行的兩個函式的變數,無法相互繫結。只有包含關係才可以。