python nonlocal的用法_简谈Python3关键字nonlocal使用场景
下面是之前提過的有待提升效率的計算移動平均的方法:
def make_averager():
series = []
def averager(new_value):
series.append(new_value)
total = sum(series)
return total/len(series)
return averager
我們在文章簡談Python閉包中設計的計算移動平均的方法效率并不高,原因是我們存儲了所有的歷史數據在列表中,然后在每次調用averager時使用sum求和。要實現同樣的功能,更好的實現方法是只存儲當前的總值和元素個數,使用這兩個值計算移動平均值即可。
直觀來思考,我們可以對代碼進行如下改進(注意:代碼有缺陷!)
def make_averager():
count = 0
total = 0
def averager(new_value):
count += 1
total += new_value
return total / count
return averager
嘗試使用該函數,會得到如下的結果:
>>> avg = make_averager()
>>> avg(10)
Traceback (most recent call last):
File "", line 1, in
File "", line 5, in averager
UnboundLocalError: local variable 'count' referenced before assignment
提示錯誤為變量count在賦值前進行了引用,實際上,total也存在相同的問題,只是count變量處提前拋出了UnboundLocalError異常。接下來進一步解釋,首先我們需要明白一個前提,在Python中,對于一個不可變數據類型比如上述示例中的count,count+=1和count=count+1是等效的。對于可變數據類型的討論,可以參考文章淺析Python中列表操作之*和*=。
因此,我們在averager的定義體中為count賦值了,這會把count變成局部變量,total變量也受這個問題影響。
先前版本沒遇到這個問題,因為我們沒有給series賦值,我們只是調用series.append,并把它傳給sum和len。也就是說,我們利用了列表是可變的對象這一事實。
但是對數字、字符串、元組等不可變類型來說,只能讀取,不能更新。如果嘗試重新綁定,例如count=count+1,其實會隱式創建局部變量count。這樣,count就不是自由變量了,因此不會保存在閉包中。
為了解決這個問題,Python3引入了nonlocal聲明。它的作用是把變量標記為自由變量,即使在函數中為變量賦予新值了,也會變成自由變量。如果為nonlocal聲明的變量賦予新值,閉包中保存的綁定會更新。最新版make_averager的正確實現如下:
def make_averager():
count = 0
total = 0
def averager(new_value):
nonlocal count, total
count += 1
total += new_value
return total / count
return averager
在Python2中沒有nonlocal關鍵字。如果要實現上面的功能需要變通的方法。基本上,這種處理方式是把內部函數需要修改的變量(如count和total)存儲為可變對象(如字典或簡單的實例)的元素或屬性,并且把那個對象綁定給一個自由變量。
至此,我們了解了Python閉包,接下來可以使用嵌套函數正式實現裝飾器了。
歡迎關注微信公眾號:CodeWorks
問題或建議,請公眾號留言,歡迎非抬杠式討論
總結
以上是生活随笔為你收集整理的python nonlocal的用法_简谈Python3关键字nonlocal使用场景的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: skywalking 安装_如何使用sk
- 下一篇: websocket python爬虫_p