6段程式碼帶你瞭解python global變數
借4個例子(現在擴到六個了<( ̄︶ ̄)>),說明一下global的作用。
a=6
print(id(a))
def f():
print(a)
print(id(a))
f()
print(id(a))
print('finally:',a)
這個程式碼能跑通,強行理解就是f內強行找了外部的a=6,使用變數a。但是如果只是簡單的找外部宣告,下邊的例子按理說也能跑通!
a=6 print(id(a)) def f(): print(a) a = 2#wrong position print(id(a)) f() print(id(a)) print('finally:',a)
但是實際上這段程式碼會報錯,因為他沒去外部找那個a=6,為什麼沒去,被a=2擋住了,儘管a=2在後邊。還是能“未卜先知”!
python是一層一層按LEGB規則向外查詢變數的宣告的。回到前邊那段成功的程式碼,唯一的區別就是查詢過程沒有a=2的阻擋。f內,print(a)前方並沒有a的宣告,但是a並沒有直接在外部找到a=6,而是發現了print後方的a=2,所以按a=2來看,但是執行起來,a=2又在print(a)之後,所以,a就被“未宣告”了!!!有點繞,簡單說,就是需要找變數的時候,找變數範圍這個動作是個不依賴程式碼順序的獨立過程,他是脫離位置關係的,但是找完了變數宣告,執行的時候,還要自上而下逐行執行!
a=6
print(id(a))
def f():
a= 2#right position!!!!!!!!
print(a)
print(id(a))
f()
print(id(a))
print('finally:',a)
改了順序,就能執行通了。
但是前邊墨跡了那麼多,你想知道的,一定不是改一下順序,規矩的執行下去,這個隨便一個傻子也能摸索著辦到。這種答案也不是本文的最終目的。本文最終程式碼如下,加global宣告,位置隨意,剛才說了,查詢宣告是脫離位置關係的,所以可以這樣宣告。這也是global關鍵字的意義。
a=6 print(id(a)) def f(): print(a) global a#wrong position print(id(a)) f() print(id(a)) print('finally:',a)
雖然這句宣告刪了也能預設產生這種效果(demo 1),能跑通,但是意義不明,也不能避免人為錯誤,預設使用規則也很抽象:只引用a就是全域性,想修改(其實是宣告)a就是區域性(這都是python宣告與賦值操作一體化的坑,用類和物件就不會這麼抽象了,最起碼你知道自己在宣告物件,而不是在賦值和修改)。寫了這句意義就明確了,使用的、和修改的,也都是同一個全域性變數。
擴充套件證明一下:既有global宣告又有賦值操作,且賦值操作在宣告前邊
下邊程式碼:先賦值a,再宣告global a,這時候a確實算global了,執行f()之後的全域性的a也確實被替換了,id變了,數值也是3,這和前例不一樣,前例只是宣告的話,id都是不變的!id改變,也證明了a是global的,證明了global宣告還是優先於a賦值操作的(原因見id測試demo5.2)。
#demo5
#assign before global declare
a = 6
print('id:',id(a))
def f():
a = 3
print('in function f() ',a)
print('id:',id(a))
global a
#a = 5#another a
print(a)
print('id:',id(a))#another a
f()
print('after f():',a)
print(id(a))
另外,這裡宣告a=5的話,還會出一個新的id,覆蓋之前的a=3的物件,仍然是一個global的物件,覆蓋全域性的a。(有沒有global都是如此,每次新的“賦值”實質都是宣告,python機制如此)
#demo5
#assign before global declare
a = 6
print('id:',id(a))
def f():
a = 3
print('in function f() ',a)
print('id:',id(a))
global a
a = 5#another a
print(a)
print('id:',id(a))#another a
f()
print('after f():',a)
print(id(a))
-------------------------------------------------
C:/numpy_demo/python_demo/global_declare.py:64: SyntaxWarning: name 'a' is assigned to before global declaration
global a
id: 1451579744
in function f() 3
id: 1451579696
5
ID: 1451579728
after f(): 5
1451579728
#demo5.2
a = 6
print('value is ',a, ' id is ',id(a))
a = 5
print('value is ',a, ' id is ',id(a))
a = 4
print('value is ',a, ' id is ',id(a))
a += 3
print('value is ',a, ' id is ',id(a))
--------------------------------------------
value is 6 id is 1451579744
value is 5 id is 1451579728
value is 4 id is 1451579712
value is 7 id is 1451579760
加一個對照組迴歸一下:不加global,執行f()之後,a仍然是6,id也沒變。
證明前例那個global是有影響到global宣告之前的a賦值操作的,這個global宣告直接使a變成了全域性物件。
#demo6
#just assign in local
a = 6
print('id:',id(a))
def f():
a = 3
print('in function f() ',a)
print('id:',id(a))
#global a
a = 5#another a
print(a)
print('id:',id(a))#another a
f()
print('after f():',a)
print(id(a))
---------------------------
id: 1451579744
in function f() 3
id: 1451579696
5
ID: 1451579728
after f(): 6
1451579744