python 的變量作用域分三種
1: local 指當前作用域
通過locals() 能獲取該命名空間的對象的dict
2:global 對應某個 .py 模塊的作用域
通過globals() 能獲取該命名空間的對象的dict
3:builtin 最頂層的作用域。
每次執行一個函數時, 就會創建新的局部命名空間。
解釋器在檢索變量的時候會按照 local》global 》builtin 的順序檢索。
比如檢索變量 test(只要該變量沒有被聲明為local變量,=, -=, += 這樣的操作會將變量聲明為local變量)會先從 local 檢索, 沒有檢索到則 檢索 global, 再沒檢索到則檢索 builtin. 如果最后沒有檢索到 則拋出 NameError的異常。
def space():
a = 21
print "local:", locals()
print "globals:", globals()
執行該函數的輸出為:
local: {'a': 21}
globals: {'__builtins__': <module '__builtin__' (built-in)>, '__file__': 'space.py', '__package__': None, 'test': <function test at 0x7fe8e0535c08>, '__name__': '__main__', '__doc__': None}
這個栗子很好理解, 那么如果
a = 31
def space():
a = 21
print "local:", locals()
print "globals:", globals()
space()
的輸出為:
local: {'a': 21}
globals: {'a': 31, '__builtins__': <module '__builtin__' (built-in)>, '__file__': 'space.py', '__package__': None, 'test': <function test at 0x7f7c0ec24c08>, '__name__': '__main__', '__doc__': None}
紅色的能很方便我們理解 local 和global 作用域的區別。
在函數里面, 只要有 =, +=, -= 這樣的賦值語句, 那么被賦值的變量就是local的
舉個栗子:
def t(a): a += 1 print "a in function:", a print "locals:", locals() a = 21 t(a)
輸出為:
a in function: 22
locals: {'a': 22}
a after invoking: 21
下面的代碼也能正常進行
def t(): if a > 1: # 檢索a會先從local作用域檢索, 然后在檢索global作用域, 發現a = 21 print "this a is global:", a print "a in function:", a print "locals:", locals() a = 21 t()
而下面的代碼會報錯:
def t(): if a > 1: print "this a is global:", a a = 3 # 此處因為有 +=, =, -= 這樣的, 所以a在該函數t內是local的, 只會在local作用域檢索a。然后上一句if a > 1會報錯 print "a in function:", a print "locals:", locals() a = 21 t()
報錯:
UnboundLocalError: local variable 'a' referenced before assignment
在函數里面,如果所傳的值是容引用,那么在函數里面對容器的修改也會修改 global作用域內的該容器。
def t(a): a['hello'] = "happy" print "a in function:", a print "locals:", locals() a = {} t(a) print "a after invoking:", a
的輸出為:
a in function: {'hello': 'happy'}
locals: {'a': {'hello': 'happy'}}
a after invoking: {'hello': 'happy'}
函數的參數默認值, test_default(下面栗子的)默認值為引用類型會在使用之后一直保存,每次對默認值的修改都會保留下來, 類似與C的靜態局部變量。但是如果自己傳了一個值來替換引用的默認值, 則不會修改保留下來的默認值。
def test_default(k, v, d = {}): d[k] = v print "d reference:", d test_default("k3", "v3", d = {}) #此處傳了一個值來替換引用的默認值, 那么修改的不是默認引用的值 test_default("k1", "v1") test_default("k2", "v2")
的輸出為:
d reference: {'k3': 'v3'}
d reference: {'k1': 'v1'}
d reference: {'k2': 'v2', 'k1': 'v1'}
lambda 里面的默認值
funcs = [lambda x, i=i: x*i for i in range(4)] print [func(2) for func in funcs]
的輸出為:
[0, 2, 4, 6]
而:
funcs = [lambda x: x*i for i in range(4)] print [func(2) for func in funcs]
的輸出為:
[6, 6, 6, 6]
函數在沒有執行前, 內部代碼不執行