python local variable_python学习笔记 - local, global and free variable
理解 global and local variable
現(xiàn)在我想在子代碼塊中對(duì)global variable重新賦值,實(shí)現(xiàn)代碼如下:
code snippet 1
>>>
>>> var = 'outer val'
>>> def func1():
... var = 'inner val'
... print "Inside func1(), val: ", var
... print "locals(): ", locals()
... print "globals(): ", globals()
...
>>> func1()
Inside func1(), val: inner val
locals(): {'var': 'inner val'}
globals(): {'func1': , '__builtins__': , '__package__': None, 'var': 'outer val', '__name__': '__main__', '__doc__': None}
>>>
>>> print "var: ", var
var: outer val
>>>
但結(jié)果并非如我所愿。在func1內(nèi)部,var的值為"inner val",離開了函數(shù),其值又變成了"outer val",為什么?看看輸出的本地和全局變量列表答案就明顯了,var既出現(xiàn)在本地變量列表,又出現(xiàn)在全局變量列表,但綁定的值不一樣,因?yàn)樗麄儽揪褪莾蓚€(gè)不同的變量。也就是說,當(dāng)你想在子代碼塊中對(duì)某個(gè)全局變量重新賦值時(shí),實(shí)際上你只是定義了一個(gè)同名的本地變量,這并不會(huì)改變?nèi)肿兞康闹怠?/p>
如何修改全局變量的值?需要在函數(shù)中使用global statement。先看一例:
code snippet 2
>>> def func2():
... global var2
... var2 = 'who am i'
... print "locals(): ", locals()
... print "globals(): ", globals()
...
>>> func2()
locals(): {}
globals(): {'func2': , 'func1': , 'var2': 'who am i', '__builtins__': , '__package__': None, '__name__': '__main__', '__doc__': None}
>>>
>>> print var2
who am i
>>>
看看輸出結(jié)果,發(fā)現(xiàn)竟然可以在函數(shù)代碼塊中定義一個(gè)全局變量,太神奇了!因?yàn)槿肿兞康淖饔糜蚴钦麄€(gè)模塊,所以離開了定義函數(shù),依然可以讀取它。
有了這個(gè)做鋪墊,再來嘗試修改全局變量的值:
code snippet 3
>>> global_var = 'outer'
>>> def func3():
... global global_var
... global_var = 'inner'
... print "locals(): ", locals()
... print "globals(): ", globals()
...
>>> func3()
locals(): {}
globals(): {'func3': , '__builtins__': , 'global_var': 'inner', '__package__': None, '__name__': '__main__', '__doc__': None}
>>>
>>> print global_var
inner
>>>
妥妥的了。做個(gè)總結(jié)吧,要在函數(shù)代碼塊中修改全局變量的值,就使用global statement聲明一個(gè)同名的全局變量,然后就可以修改其值了;如果事先不存在同名全局變量,此語句就會(huì)定義一個(gè),即使離開了當(dāng)前函數(shù)也可以使用它。
理解 global and free variable
來自于python官方文檔 Execution Model 的解釋:
When a name is used in a code block, it is resolved using the nearest enclosing scope. The set of all such scopes visible to a code block is called the block’s environment.
If a name is bound in a block, it is a local variable of that block. If a name is bound at the module level, it is a global variable. (The variables of the module code block are local and global.) If a variable is used in a code block but not defined there, it is a free variable.
這段文檔確實(shí)應(yīng)該多讀多想。全局變量不用多說,一看就懂。不過這句話有點(diǎn)讓人費(fèi)解,“The variables of the module code block are local and global”,我是這樣理解的,對(duì)于模塊代碼塊來說,模塊級(jí)的變量就是它的本地變量,但對(duì)于模塊中其他更小的代碼塊來說,這些變量就是全局的。那再進(jìn)一步,什么是模塊級(jí)的變量,是指那些在模塊內(nèi)部,但在其所有子代碼塊之外定義的變量嗎?用代碼驗(yàn)證哈:
code snippet 4
>>>
>>> global_var = 'global_val'
>>> def showval():
... local_var = 'local_val'
... print "before defining inner func, showval.locals(): ", locals()
... def innerFunc():
... print "Inside innerFunc, local_var: ", local_var
... print "innerFunc.locals:", locals()
... print "after defining inner func, showval.locals(): ", locals()
... print "showval.globals():", globals()
... return innerFunc
...
>>> a_func = showval()
before defining inner func, showval.locals(): {'local_var': 'local_val'}
after defining inner func, showval.locals(): {'innerFunc': , 'local_var': 'local_val'}
showval.globals(): {'__builtins__': , 'global_var': 'global_val', '__package__': None, '__name__': '__main__', '__doc__': None, 'showval': }
>>>
>>> a_func
>>> a_func()
Inside innerFunc, local_var: local_val
innerFunc.locals: {'local_var': 'local_val'}
>>>
基于自己的理解來分析哈輸出結(jié)果:變量local_var、函數(shù)innerFunc是在函數(shù)代碼塊showval中定義的,所以它們是該代碼塊的局部變量。首次輸出globals時(shí),變量global_var、函數(shù)showval在所有子代碼塊之外定義,所以它們是當(dāng)前模塊的全局變量。再次輸出globals時(shí),多了一個(gè)全局變量globals。
注意看,全局變量中還有:__builtins__、__package__、__name__、__doc__。這些變量的含義可參考 python模塊的內(nèi)置方法。
現(xiàn)在來看自由變量,local_var被innerFunc函數(shù)使用,但是并未在其中定義,所以對(duì)于innerFunc代碼塊來說,它就是自由變量。問題來了,自由變量為什么出現(xiàn)在
innerFunc.locals()的輸出結(jié)果中?這就需要看看locals()API文檔了:
Update and return a dictionary representing the current local symbol table. Free variables are returned by locals() when it is called in function blocks, but not in class blocks.
好像我已經(jīng)把自由變量搞得很清楚了,但是真的嗎?看看下面的代碼:
code snippet 5
>>>
>>> global_var = 'foo'
>>> def ex1():
... local_var = 'bar'
... print "locals(): ", locals()
... print global_var
... print local_var
... global_var = 'foo2'
...
>>> ex1()
locals(): {'local_var': 'bar'}
Traceback (most recent call last):
File "", line 1, in
File "", line 4, in ex1
UnboundLocalError: local variable 'global_var' referenced before assignment
>>>
>>> def ex2():
... local_var = 'bar'
... print "locals(): ", locals()
... print "globals(): ", globals()
... print global_var
... print local_var
...
>>> ex2()
locals(): {'local_var': 'bar'}
globals(): {'__builtins__': , 'global_var': 'foo', '__package__': None, 'ex2': , 'ex1': , '__name__': '__main__', '__doc__': None}
foo
bar
>>>
首先分析哈輸出結(jié)果。執(zhí)行ex1()函數(shù)失敗,原因:UnboundLocalError: local variable 'global_var' referenced before assignment,意思是global_var這個(gè)本地變量還未賦值就被引用了。等等,global_var怎么是本地變量了?與ex2()函數(shù)做個(gè)對(duì)比,發(fā)現(xiàn)因?yàn)橛羞@行代碼global_var = 'foo2',解釋器就認(rèn)為global_var是一個(gè)本地變量,而不是全局變量。
那最外面定義的global_var到底是本地還是全局變量?看看第二部分的輸出,可以很確定地知道最外面定義的global_var是一個(gè)全局變量。
簡(jiǎn)單點(diǎn)說,就是這里存在兩個(gè)同名的變量,一個(gè)是最外面定義的全局變量global_var,另一個(gè)是函數(shù)ex1()中定義的本地變量global_var。
再等等,矛盾出現(xiàn)了。按照之前對(duì)自由變量的理解,在一個(gè)代碼塊中被使用,但是并未在那兒定義,外部定義的global_var在函數(shù)塊ex1()中被使用,完全符合,它為什么不是一個(gè)自由變量?還是我們對(duì)自由變量的理解有問題?
與code snippet 4中確定是自由變量的local_var比較,發(fā)現(xiàn)local_var是一個(gè)函數(shù)代碼塊的本地變量,而code snippet 5中的global_var是一個(gè)模塊代碼塊的本地變量。當(dāng)local_var被定義它的函數(shù)內(nèi)的嵌套函數(shù)使用時(shí),它就變成了一個(gè)自由變量,此時(shí)函數(shù)的嵌套就形成了閉包(closure),可見自由變量的應(yīng)用場(chǎng)景就是閉包。
而global_var對(duì)模塊本身來說它是一個(gè)本地變量,但在模塊中的其他代碼塊中也可以使用它,所以它同時(shí)又是一個(gè)全局變量。
到這兒就可以對(duì)自由變量的理解做個(gè)總結(jié)了:如果一個(gè)變量在函數(shù)代碼塊中定義,但在其他代碼塊中被使用,例如嵌套在外部函數(shù)中的閉包函數(shù),那么它就是自由變量。注意,給變量賦值不算是使用該變量,使用指的是讀取變量值,具體區(qū)別后面再詳述。
理解 free and local variable
修改全局變量的值需要使用global,那修改自由變量的值又會(huì)如何?先用自然思維方式試試:
code snippet 6
>>>
>>> def outerfunc():
... var = 'free'
... def innerfunc():
... var = 'inner'
... print "Inside innerfunc, var: ", var
... print "Inside innerfunc, locals(): ", locals()
... innerfunc()
... print "var: ", var
... print "locals(): ", locals()
...
>>> outerfunc()
Inside innerfunc, var: inner
Inside innerfunc, locals(): {'var': 'inner'}
var: free
locals(): {'var': 'free', 'innerfunc': }
>>>
在innerfunc函數(shù)中我試圖修改自由變量var的值,結(jié)果卻發(fā)現(xiàn)修改只在innerfunc函數(shù)內(nèi)有效,離開此函數(shù)后其值仍然是"free"。看看輸出的outerfunc和innerfunc函數(shù)的本地變量列表就知道咋回事兒了。當(dāng)你想在閉包函數(shù)中對(duì)自由變量重新賦值時(shí),實(shí)際上你只是在這里定義了一個(gè)本地變量,這并不會(huì)改變自由變量的值。
code snippet 7
class Namespace: pass
def ex7():
ns = Namespace()
ns.var = 'foo'
def inner():
ns.var = 'bar'
print 'inside inner, ns.var is ', ns.var
inner()
print 'inside outer function, ns.var is ', ns.var
ex7()
# console output
inside inner, ns.var is bar
inside outer function, ns.var is bar
code snippet 8
def ex8():
ex8.var = 'foo'
def inner():
ex8.var = 'bar'
print 'inside inner, ex8.var is ', ex8.var
inner()
print 'inside outer function, ex8.var is ', ex8.var
ex8()
# console output
inside inner, ex8.var is bar
inside outer function, ex8.var is bar
參考資源:
與50位技術(shù)專家面對(duì)面20年技術(shù)見證,附贈(zèng)技術(shù)全景圖總結(jié)
以上是生活随笔為你收集整理的python local variable_python学习笔记 - local, global and free variable的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 鲜花椒怎么腌好吃呢?
- 下一篇: 14个人吃饭点几个菜合适