python nonlocal global 变量作用域
之前在討論閉包的時候有提到:
Python會按LEGB的順序來搜索變量:
要說明的是,這里的訪問規則只對普通變量有效, 對象屬性的規則與這無關(簡單地說,訪問一個對象的屬性與此無關)。
L. Local. 局部作用域,即函數中定義的變量(沒有用global聲明)
E. Enclosing. 嵌套的父級函數的局部作用域,即包含此函數的上級函數的局部作用域,比如上面的示例中的labmda所訪問的x就在其父級函數test的局部作用域里。通常也叫non-local作用域。
G. Global(module). 在模塊級別定義的全局變量(如果需要在函數內修改它,需要用global聲明)
B. Built-in. built-in模塊里面的變量,比如int, Exception等等
但此規則有一個重要的限制:
一個不在局部作用域里的變量默認是只讀的,如果試圖為其綁定一個新的值, Python認為是在當前的局部作用域里創建一個新的變量
如果確實要在一個函數里修改全局變量,Python提供了global關鍵字來聲明一個變量是全局變量,聲明以后就可以修改其值了。 然而global只能用來修改全局作用域里的變量,對于嵌套函數的情況無能為力,所以計數器的例子在Python 2.x中是無法實現的。
然而在Python 3中,一個新的關鍵字nonlocal的產生解決了這個問題
計數器:
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來實現類似的計數器
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上看到這個問題時卻沒有及時反應過來:
問題:
這段代碼不用在函數中聲明global x就可以打印出x的值
x = 20
def getx():
print x
getx()
那請問在哪些情況下必須要使用global聲明全局變量?
以下是一個多線程的python代碼片段,其中的x,l都是全局變量,但在threadcode()函數中只聲明了global x沒有global l。完整的代碼是可以成功運行,但是把global x注釋掉后就會報錯。請問這是為什么,Lock對象比較特殊嗎?
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()
...
解答:
對于Python2而言,對于一個全局變量,你的函數里如果只使用到了它的值,而沒有對其賦值(指a = XXX這種寫法)的話,就不需要聲明global。相反,如果你對其賦了值的話,那么你就需要聲明global。聲明global的話,就表示你是在向一個全局變量賦值,而不是在向一個局部變量賦值。
global關鍵字用來在函數或其他局部作用域中使用全局變量。但是如果不修改全局變量也可以不使用global關鍵字。
nonlocal關鍵字用來在函數或其他作用域中使用外層(非全局)變量。
總結
以上是生活随笔為你收集整理的python nonlocal global 变量作用域的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 日本银行存款利率是多少
- 下一篇: jieba.analyse jieba