亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

Python中的閉包實例詳解

系統 1700 0

一般來說閉包這個概念在很多語言中都有涉及,本文主要談談python中的閉包定義及相關用法。Python中使用閉包主要是在進行函數式開發時使用。詳情分析如下:

一、定義

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

            
>>>def addx(x): 
>>> def adder(y): return x + y 
>>> return adder 
>>> c = addx(8) 
>>> type(c) 

            
               
>>> 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 "
            
              ", line 1, in 
              
                 
 File "
                
                  ", 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 之前,使用語句nonlocal 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程序設計有一定的借鑒價值。


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦?。?!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 成人a在线 | 国产精品久久久亚洲动漫 | 天天做天天玩天天爽天天 | 免费观看一区二区 | 亚洲精品久久久久中文字幕一区 | 这里只有久久精品 | 一级毛片视频免费观看 | 久久国产精品成人免费 | 久久香蕉久久 | 婷婷色网| 国产91在线精品福利 | 九九热这里都是精品 | 精品久久中文久久久 | 亚洲麻豆国产精品 | 亚洲国产精品a一区二区三区 | 国产精品香蕉在线一区 | 91视频国产高清 | 国产精品国产自线拍手机观看 | 欧美毛片网| 一级毛片a女人刺激视频免费 | 亚洲免费毛片 | 国产毛片在线高清视频 | 欧美国产日韩在线播放 | 2019av在线视频 | 亚洲一区二区中文字5566 | 亚洲欧美在线看 | 欧美白人猛性xxxxx交69 | 久久精品国产亚洲综合色 | 久久精品免费在线观看 | 奇米网在线观看 | 高清视频在线播放 | 九九亚洲综合精品自拍 | 亚洲小视频在线 | h片在线播放免费高清 | 天天天操 | 国产码欧美日韩高清综合一区 | 日韩精品欧美一区二区三区 | 亚洲男人的天堂久久无 | 日本免费三区 | 婷婷综合亚洲 | 内衣办公室动漫久久影院 |