日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

Python-闭包详解

發布時間:2025/3/15 python 14 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Python-闭包详解 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.


在函數編程中經常用到閉包。閉包是什么,它是怎么產生的及用來解決什么問題呢。給出字面的定義先:閉包是由函數及其相關的引用環境組合而成的實體(即:閉包=函數+引用環境)(想想Erlang的外層函數傳入一個參數a, 內層函數依舊傳入一個參數b, 內層函數使用a和b, 最后返回內層函數)。這個從字面上很難理解,特別對于一直使用命令式語言進行編程的程序員們。本文將結合實例代碼進行解釋。
函數是什么
地球人都知道:函數只是一段可執行代碼,編譯后就“固化”了,每個函數在內存中只有一份實例,得到函數的入口點便可以執行函數了。在函數式編程語言中,函 數是一等公民(First class value:第一類對象,我們不需要像命令式語言中那樣借助函數指針,委托操作函數),函數可以作為另一個函數的參數或返回值,可以賦給一個變量。函數可 以嵌套定義,即在一個函數內部可以定義另一個函數,有了嵌套函數這種結構,便會產生閉包問題。如:

>>>?def?ExFunc(n):
?????sum=n
?????def?InsFunc():
?????????????return?sum+1
?????return?InsFunc

>>>?myFunc=ExFunc(10)
>>>?myFunc()
11
>>>?myAnotherFunc=ExFunc(20)
>>>?myAnotherFunc()
21
>>>?myFunc()
11
>>>?myAnotherFunc()
21
>>>

在這段程序中,函數InsFunc是函數ExFunc的內嵌函數,并且是ExFunc函數的返回值。我們注意到一個問題:內嵌函數InsFunc中 引用到外層函數中的局部變量sum,IronPython會這么處理這個問題呢?先讓我們來看看這段代碼的運行結果。當我們調用分別由不同的參數調用 ExFunc函數得到的函數時(myFunc(),myAnotherFunc()),得到的結果是隔離的,也就是說每次調用ExFunc函數后都將生成并保存一個新的局部變量sum。其實這里ExFunc函數返回的就是閉包。

引用環境
按照命令式語言的規則,ExFunc函數只是返回了內嵌函數InsFunc的地址,在執行InsFunc函數時將會由于在其作用域內找不到sum變量而出 錯。而在函數式語言中,當內嵌函數體內引用到體外的變量時,將會把定義時涉及到的引用環境和函數體打包成一個整體(閉包)返回。現在給出引用環境的定義就 容易理解了:引用環境是指在程序執行中的某個點所有處于活躍狀態的約束(一個變量的名字和其所代表的對象之間的聯系)所組成的集合。閉包的使用和正常的函 數調用沒有區別。

由于閉包把函數和運行時的引用環境打包成為一個新的整體,所以就解決了函數編程中的嵌套所引發的問題。如上述代碼段中,當每次調用ExFunc函數 時都將返回一個新的閉包實例,這些實例之間是隔離的,分別包含調用時不同的引用環境現場。不同于函數,閉包在運行時可以有多個實例,不同的引用環境和相同 的函數組合可以產生不同的實例。

?一,定義
python中的閉包從表現形式上定義(解釋)為:如果在一個內部函數里,對在外部作用域(但不是在全局作用域)的變量進行引用,那么內部函數就被認為是閉包(closure).這個定義是相對直白的,好理解的,不像其他定義那樣學究味道十足(那些學究味道重的解釋,在對一個名詞的解釋過程中又充滿了一堆讓人抓狂的其他陌生名詞,不適合初學者)。下面舉一個簡單的例子來說明。

>>>def addx(x): >>> def adder(y): return x + y >>> return adder >>> c = addx(8) >>> type(c) <type 'function'> >>> c.__name__ 'adder' >>> c(10) 18

結合這段簡單的代碼和定義來說明閉包:
如果在一個內部函數里:adder(y)就是這個內部函數,
對在外部作用域(但不是在全局作用域)的變量進行引用:x就是被引用的變量,x在外部作用域addx里面,但不在全局作用域里,
則這個內部函數adder就是一個閉包。

再稍微講究一點的解釋是,閉包=函數塊+定義函數時的環境,adder就是函數塊,x就是環境,當然這個環境可以有很多,不止一個簡單的x。

二,使用閉包注意事項
1,閉包中是不能修改外部作用域的局部變量的

>>> def foo(): ... m = 0 ... def foo1(): ... m = 1 ... print m ... ... print m ... foo1() ... print m ... >>> foo() 0 1 0

從執行結果可以看出,雖然在閉包里面也定義了一個變量m,但是其不會改變外部函數中的局部變量m。

2,以下這段代碼是在python中使用閉包時一段經典的錯誤代碼

def foo(): a = 1 def bar(): a = a + 1 return a return bar

這段程序的本意是要通過在每次調用閉包函數時都對變量a進行遞增的操作。但在實際使用時

>>> c = foo() >>> print c() Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 4, in bar UnboundLocalError: local variable 'a' referenced before assignment

這是因為在執行代碼 c = foo()時,python會導入全部的閉包函數體bar()來分析其的局部變量,python規則指定所有在賦值語句左面的變量都是局部變量,則在閉包bar()中,變量a在賦值符號"="的左面,被python認為是bar()中的局部變量。再接下來執行print c()時,程序運行至a = a + 1時,因為先前已經把a歸為bar()中的局部變量,所以python會在bar()中去找在賦值語句右面的a的值,結果找不到,就會報錯。解決的方法很簡單

def foo(): a = [1] def bar(): a[0] = a[0] + 1 return a[0] return bar

只要將a設定為一個容器就可以了。這樣使用起來多少有點不爽,所以在python3以后,在a = a + 1 之前,使用語句nonloacal a就可以了,該語句顯式的指定a不是閉包的局部變量。

3,還有一個容易產生錯誤的事例也經常被人在介紹python閉包時提起,我一直都沒覺得這個錯誤和閉包有什么太大的關系,但是它倒是的確是在python函數式編程是容易犯的一個錯誤,我在這里也不妨介紹一下。先看下面這段代碼

for i in range(3): print i

在程序里面經常會出現這類的循環語句,Python的問題就在于,當循環結束以后,循環體中的臨時變量i不會銷毀,而是繼續存在于執行環境中。還有一個python的現象是,python的函數只有在執行時,才會去找函數體里的變量的值。

flist = [] for i in range(3): def foo(x): print x + i flist.append(foo) for f in flist: f(2)

可能有些人認為這段代碼的執行結果應該是2,3,4.但是實際的結果是4,4,4。這是因為當把函數加入flist列表里時,python還沒有給i賦值,只有當執行時,再去找i的值是什么,這時在第一個for循環結束以后,i的值是2,所以以上代碼的執行結果是4,4,4.
解決方法也很簡單,改寫一下函數的定義就可以了。

for i in range(3): def foo(x,y=i): print x + y flist.append(foo)

三,作用
說了這么多,不免有人要問,那這個閉包在實際的開發中有什么用呢?閉包主要是在函數式開發過程中使用。以下介紹兩種閉包主要的用途。

用途1,當閉包執行完后,仍然能夠保持住當前的運行環境。
比如說,如果你希望函數的每次執行結果,都是基于這個函數上次的運行結果。我以一個類似棋盤游戲的例子來說明。假設棋盤大小為50*50,左上角為坐標系原點(0,0),我需要一個函數,接收2個參數,分別為方向(direction),步長(step),該函數控制棋子的運動。棋子運動的新的坐標除了依賴于方向和步長以外,當然還要根據原來所處的坐標點,用閉包就可以保持住這個棋子原來所處的坐標。

origin = [0, 0] # 坐標系統原點 legal_x = [0, 50] # x軸方向的合法坐標 legal_y = [0, 50] # y軸方向的合法坐標 def create(pos=origin): def player(direction,step): # 這里應該首先判斷參數direction,step的合法性,比如direction不能斜著走,step不能為負等 # 然后還要對新生成的x,y坐標的合法性進行判斷處理,這里主要是想介紹閉包,就不詳細寫了。 new_x = pos[0] + direction[0]*step new_y = pos[1] + direction[1]*step pos[0] = new_x pos[1] = new_y #注意!此處不能寫成 pos = [new_x, new_y],原因在上文有說過 return pos return player player = create() # 創建棋子player,起點為原點 print player([1,0],10) # 向x軸正方向移動10步 print player([0,1],20) # 向y軸正方向移動20步 print player([-1,0],10) # 向x軸負方向移動10步

輸出為

[10, 0] [10, 20] [0, 20]

用途2,閉包可以根據外部作用域的局部變量來得到不同的結果,這有點像一種類似配置功能的作用,我們可以修改外部的變量,閉包根據這個變量展現出不同的功能。比如有時我們需要對某些文件的特殊行進行分析,先要提取出這些特殊行。

def make_filter(keep): def the_filter(file_name): file = open(file_name) lines = file.readlines() file.close() filter_doc = [i for i in lines if keep in i] return filter_doc return the_filter

如果我們需要取得文件"result.txt"中含有"pass"關鍵字的行,則可以這樣使用例子程序

filter = make_filter("pass") filter_result = filter("result.txt")

以上兩種使用場景,用面向對象也是可以很簡單的實現的,但是在用Python進行函數式編程時,閉包對數據的持久化以及按配置產生不同的功能,是很有幫助的。

總結

以上是生活随笔為你收集整理的Python-闭包详解的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 天天操天天射天天爽 | 九九操| 婷婷五综合 | 香蕉污视频在线观看 | 久久77777 | 黄色aa网站| 小泽玛利亚一区二区三区在线观看 | youjizz国产精品| 麻豆高清视频 | 欧美老肥熟 | 在线视频一区二区 | 特级新鲜大片片 | a级片在线看| 色在线播放 | 国产在线一区二区三区四区 | 久久精品a亚洲国产v高清不卡 | 艳母免费在线观看 | 不许穿内裤随时挨c调教h苏绵 | 我要看黄色大片 | 国产色av | 日韩在线视频免费看 | 天天色棕合合合合合合合 | 久久久久久免费观看 | 亚洲视频一区二区三区在线观看 | 狠狠操网站| 五月婷婷六月天 | 亚洲国产成人精品女人久久 | 蜜桃免费在线视频 | 少妇高潮av久久久久久 | 大吊av| 欧美一卡二卡在线观看 | 欧美日韩国产综合网 | 日韩特级黄色片 | 日本东京热一区二区三区 | 加勒比成人在线 | jlzzjlzz国产精品久久 | 国产绿帽一区二区三区 | 免费看片亚洲 | 亚洲色图国产视频 | 成人激情在线观看 | 五月天中文字幕在线 | 天堂影视在线观看 | 欧美一a一片一级一片 | 日本精品久久 | 九九热国产视频 | 天天做天天爱天天爽综合网 | 中文字幕免费在线看线人动作大片 | 国产女主播喷水视频在线观看 | 国模少妇一区二区 | 四虎影视免费在线观看 | 可以免费看av | 国产一级免费大片 | 成 人 黄 色 片 在线播放 | 无码人妻av一区二区三区波多野 | 人妻 日韩 欧美 综合 制服 | 欧美久久网 | 国产精品无码人妻一区二区在线 | 成人深夜影院 | babes性欧美69| 国产一区二区三区麻豆 | 成人国产免费视频 | 在线免费国产视频 | 国产精品精品国产色婷婷 | 国产经典一区二区三区 | 久操视频网 | 蜜臀久久99精品久久久久宅男 | 丝袜美腿亚洲一区二区图片 | 玖玖精品视频 | 久久资源365| 伊人77 | 在线播放的av | 久久高清内射无套 | 中国黄色免费 | 女生裸体无遮挡 | 骚狐网站 | 风流老熟女一区二区三区 | 日韩手机在线观看 | 真性中出 | 欧美理论在线 | 国产精品国语自产拍在线观看 | 动漫av网 | 人人澡人人爱 | 超碰97自拍 | 成人精品av | 精品在线观看免费 | 久久久久久午夜 | 成人激情片 | 性生生活性生交a级 | 久久久三区 | 亚洲激情午夜 | 波多野吉衣av在线 | 中文字幕视频免费 | 国产日本欧美在线观看 | 91亚洲欧美激情 | 亚洲精品国偷拍自产在线观看蜜桃 | 国产主播毛片 | 草草影院在线免费观看 | 久久99这里只有精品 | 麻豆免费电影 |