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

 

git鏈接

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章