python nonlocal global 变量作用域
之前在討論閉包的時(shí)候有提到:
Python會(huì)按LEGB的順序來(lái)搜索變量:
要說(shuō)明的是,這里的訪問(wèn)規(guī)則只對(duì)普通變量有效, 對(duì)象屬性的規(guī)則與這無(wú)關(guān)(簡(jiǎn)單地說(shuō),訪問(wèn)一個(gè)對(duì)象的屬性與此無(wú)關(guān))。
L. Local. 局部作用域,即函數(shù)中定義的變量(沒(méi)有用global聲明)
E. Enclosing. 嵌套的父級(jí)函數(shù)的局部作用域,即包含此函數(shù)的上級(jí)函數(shù)的局部作用域,比如上面的示例中的labmda所訪問(wèn)的x就在其父級(jí)函數(shù)test的局部作用域里。通常也叫non-local作用域。
G. Global(module). 在模塊級(jí)別定義的全局變量(如果需要在函數(shù)內(nèi)修改它,需要用global聲明)
B. Built-in. built-in模塊里面的變量,比如int, Exception等等
但此規(guī)則有一個(gè)重要的限制:
一個(gè)不在局部作用域里的變量默認(rèn)是只讀的,如果試圖為其綁定一個(gè)新的值, Python認(rèn)為是在當(dāng)前的局部作用域里創(chuàng)建一個(gè)新的變量
如果確實(shí)要在一個(gè)函數(shù)里修改全局變量,Python提供了global關(guān)鍵字來(lái)聲明一個(gè)變量是全局變量,聲明以后就可以修改其值了。 然而global只能用來(lái)修改全局作用域里的變量,對(duì)于嵌套函數(shù)的情況無(wú)能為力,所以計(jì)數(shù)器的例子在Python 2.x中是無(wú)法實(shí)現(xiàn)的。
然而在Python 3中,一個(gè)新的關(guān)鍵字nonlocal的產(chǎn)生解決了這個(gè)問(wèn)題
計(jì)數(shù)器:
def make_counter():
count = 0
def counter():
nonlocal count
count += 1
return count
return counter
def make_counter_test():
mc = make_counter()
print(mc())
print(mc())
print(mc())
也可以使用generator來(lái)實(shí)現(xiàn)類似的計(jì)數(shù)器
def counter_generator():
count = 0
while True:
count += 1
yield count
def counter_generator_test():
# below is for python 3.x and works well
citer = counter_generator().__iter__()
i = 0
while(i < 3) :
print(citer.__next__())
i+=1
而今天在segmentfault上看到這個(gè)問(wèn)題時(shí)卻沒(méi)有及時(shí)反應(yīng)過(guò)來(lái):
問(wèn)題:
這段代碼不用在函數(shù)中聲明global x就可以打印出x的值
x = 20
def getx():
print x
getx()
那請(qǐng)問(wèn)在哪些情況下必須要使用global聲明全局變量?
以下是一個(gè)多線程的python代碼片段,其中的x,l都是全局變量,但在threadcode()函數(shù)中只聲明了global x沒(méi)有global l。完整的代碼是可以成功運(yùn)行,但是把global x注釋掉后就會(huì)報(bào)錯(cuò)。請(qǐng)問(wèn)這是為什么,Lock對(duì)象比較特殊嗎?
import threading, time, sys
x = 50
l = threading.Lock()
def threadcode():
global x
l.acquire()
print 'Thread %s invoked.' % threading.currentThread().getName()
try:
print 'Thread %s running.' % threading.currentThread().getName()
x = x + 50
print 'Thread %s set x to %d.' % \
(threading.currentThread().getName(), x)
finally:
l.release()
...
解答:
對(duì)于Python2而言,對(duì)于一個(gè)全局變量,你的函數(shù)里如果只使用到了它的值,而沒(méi)有對(duì)其賦值(指a = XXX這種寫法)的話,就不需要聲明global。相反,如果你對(duì)其賦了值的話,那么你就需要聲明global。聲明global的話,就表示你是在向一個(gè)全局變量賦值,而不是在向一個(gè)局部變量賦值。
global關(guān)鍵字用來(lái)在函數(shù)或其他局部作用域中使用全局變量。但是如果不修改全局變量也可以不使用global關(guān)鍵字。
nonlocal關(guān)鍵字用來(lái)在函數(shù)或其他作用域中使用外層(非全局)變量。
總結(jié)
以上是生活随笔為你收集整理的python nonlocal global 变量作用域的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 日本银行存款利率是多少
- 下一篇: jieba.analyse jieba