国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

可愛的Python函數式編程(二)

開發 后端
在我講解函數式編程的上一篇文章,第一部分,中,我介紹了FP中的一些基本概念。 本文將更加深入的對這個內容十分豐富的概念領域進行探討。在我們探討的大部分內容中,Bryn Keller的"Xoltar Toolkit"為我們提供一些非常有價值的幫助作用。

摘要:本專欄繼續讓David對Python中的函數式編程(FP)進行介紹。讀完本文,可以享受到使用不同的編程范型(paradigm)解決問題所帶來的樂趣。David在本文中對FP中的多個中級和高級概念進行了詳細的講解。

一個對象就是附有若干過程(procedure)的一段數據。。。一個閉包(closure)就是附有一段數據的一個過程(procedure)。

在我講解函數式編程的上一篇文章,第一部分,中,我介紹了FP中的一些基本概念。 本文將更加深入的對這個內容十分豐富的概念領域進行探討。在我們探討的大部分內容中,Bryn Keller的"Xoltar Toolkit"為我們提供一些非常有價值的幫助作用。Keller將FP中的許多強項集中到了一個很棒且很小的模塊中,他在這個模塊中用純Python代碼實現了這些強項。除了functional模塊外,Xoltar Toolkit還包含了一個延遲(lazy)模塊,對“僅在需要時”才進行求值提供了支持。許多傳統的函數式語言中也都具有延遲求值的手段,這樣,使用Xoltar Toolkit中的這些組件,你就可以做到使用象Haskell這樣的函數式語言能夠做到的大部分事情了。

綁定(Binding)

有心的讀者會記得,我在第一部分中所述的函數式技術中指出過Python的一個局限。具體講,就是Python中沒有任何手段禁止對用來指代函數式表達式的名字進行重新綁定。 在FP中,名字一般是理解為對比較長的表達式的簡稱,但這里面隱含了一個諾言,就是“同一個表達式總是具有同一個值”。如果對用來指代的名字重新進行綁定,就會違背這個諾言。例如, 假如我們如以下所示,定義了一些要用在函數式程序中的簡記表達式:

Python中由于重新綁定而引起問題的FP編程片段

  1. >>> car = lambda lst: lst[0]  
  2. >>> cdr = lambda lst: lst[1:]  
  3. >>> sum2 = lambda lst: car(lst)+car(cdr(lst))  
  4. >>> sum2(range(10))  
  5. 1 
  6. >>> car = lambda lst: lst[2]  
  7. >>> sum2(range(10))  
  8. 5 

非常不幸,程序中完全相同的表達式sum2(range(10))在兩個不同的點求得的值卻不相同, 盡管在該表達式的參數中根本沒有使用任何可變的(mutable)變量。

幸運的是, functional模塊提供了一個叫做Bindings(由鄙人向Keller進行的提議,proposed to Keller by yours truly)的類,可以用來避免這種重新綁定(至少可以避免意外的重新綁定,Python并不阻止任何拿定主意就是要打破規則的程序員)。盡管要用Bindings類就需要使用一些額外的語法,但這么做就能讓這種事故不太容易發生。 Keller在functional模塊里給出的例子中,有個Bindings的實例名字叫做let(我推測這么叫是為了仿照ML族語言中的let關鍵字)。例如,我們可以這么做:

Python中對重新綁定進行監視后的FP編程片段

  1. >>> from functional import *  
  2. >>> let = Bindings()  
  3. >>> let.car = lambda lst: lst[0]  
  4. >>> let.car = lambda lst: lst[2]  
  5. Traceback (innermost last):  
  6.   File "<stdin>", line 1in ?  
  7.   File "d:\tools\functional.py", line 976in __setattr__  
  8.     raise BindingError, "Binding '%s' cannot be modified." % name  
  9. functional.BindingError:  Binding 'car' cannot be modified.  
  10. >>> car(range(10))  
  11. 0 

顯而易見,在真正的程序中應該去做一些事情,捕獲這種"BindingError"異常,但發出這些異常這件事,就能夠避免產生這一大類的問題。

functional模塊隨同Bindings一起還提供了一個叫做namespace的函數,這個函數從Bindings實例中弄出了一個命名空間 (實際就是個字典) 。如果你想計算一個表達式,而該表達式是在定義于一個Bindings中的一個(不可變)命名空間中時,這個函數就可以很方便地拿來使用。Python的eval()函數允許在命名空間中進行求值。舉個例子就能說明這一切:

Python中使用不可變命名空間的FP編程片段

  1. >>> let = Bindings()      # "Real world" function names  
  2. >>> let.r10 = range(10)  
  3. >>> let.car = lambda lst: lst[0]  
  4. >>> let.cdr = lambda lst: lst[1:]  
  5. >>> eval('car(r10)+car(cdr(r10))', namespace(let))  
  6. >>> inv = Bindings()      # "Inverted list" function names  
  7. >>> inv.r10 = let.r10  
  8. >>> inv.car = lambda lst: lst[-1]  
  9. >>> inv.cdr = lambda lst: lst[:-1]  
  10. >>> eval('car(r10)+car(cdr(r10))', namespace(inv))  
  11. 17 

閉包(Closure)

FP中有一個特別有引人關注的概念叫做閉包。實際上,閉包充分引起了很多程序員的關注,即使通常意義上的非函數式編程語言,比如Perl和Ruby,都包含了閉包這一特性。此外,Python 2.1 目前一定會添加上詞法域(lexical scoping), 這樣一來就提供的閉包的絕大多數功能。

那么,閉包到底是什么?Steve Majewski最近在Python新聞組中對這個概念的特性提出了一個準確的描述:

就是說,閉包就象是FP的Jekyll,OOP(面向對象編程)的 Hyde (或者可能是將這兩個角色互換)(譯者注:Jekyll和Hyde是一部小說中的兩個人物). 和象對象實例類似,閉包是一種把一堆數據和一些功能打包一起進行傳遞的手段。

先讓我們后退一小步,看看對象和閉包都能解決一些什么樣的問題,然后再看看在兩樣都不用的情況下這些問題是如何得到解決的。函數返回的值通常是由它在計算過程中使用的上下文決定的。最常見可能也是最顯然的指定該上下文的方式就是給函數傳遞一些參數,讓該函數對這些參數進行一些運算。但有時候在參數的“背景”(background)和“前景”(foreground)兩者之間也有一種自然的區分,也就是說,函數在某特定時刻正在做什么和函數“被配置”為處于多種可能的調用情況之下這兩者之間有不同之處。

在集中處理前景的同時,有多種方式進行背景處理。一種就是“忍辱負重”,每次調用時都將函數需要的每個參數傳遞給函數。這通常就相對于在函數調用鏈中不斷的將很多值(或者是一個具有很多字段的數據結構)傳上傳下,就是因為在鏈中的某個地方可能會用到這些值。下面舉個簡單的例子:

用了貨船變量的Python代碼片段

  1. >>> def a(n):  
  2. ...     add7 = b(n)  
  3. ...     return add7  
  4. ...  
  5. >>> def b(n):  
  6. ...     i = 7 
  7. ...     j = c(i,n)  
  8. ...     return j  
  9. ...  
  10. >>> def c(i,n):  
  11. ...     return i+n  
  12. ...  
  13. >>> a(10)     # Pass cargo value for use downstream  
  14. 17 

在上述的貨船變量例子中,函數b()中的變量n毫無意義,就只是為了傳遞給函數c()。另一種辦法是使用全局變量:

使用全局變量的Python代碼片段

  1. >>> N = 10 
  2. >>> def  addN(i):  
  3. ...     global N  
  4. ...     return i+N  
  5. ...  
  6. >>> addN(7)   # Add global N to argument  
  7. 17 
  8. >>> N = 20 
  9. >>> addN(6)   # Add global N to argument  
  10. 26 

全局變量N只要你想調用ddN()就可以直接使用,就不需要顯式地傳遞這個全局背景“上下文”了。有個稍微更加Python化的技巧,可以用來在定義函數時,通過使用缺省參數將一個變量“凍結”到該函數中:

使用凍結變量的Python代碼片段

  1. >>> N = 10 
  2. >>> def addN(i, n=N):  
  3. ...     return i+n  
  4. ...  
  5. >>> addN(5)   # Add 10  
  6. 15 
  7. >>> N = 20 
  8. >>> addN(6)   # Add 10 (current N doesn't matter)  
  9. 16 

我們凍結的變量實質上就是個閉包。我們將一些數據“附加”到了addN()函數之上。對于一個完整的閉包而言,在函數addN()定義時所出現的數據,應該在該函數被調用時也可以拿到。然而,本例中(以及更多更健壯的例子中),使用缺省參數讓足夠的數據可用非常簡單。函數addN()不再使用的變量因而對計算結構捕獲產生絲毫影響。

現在讓我們再看一個用OOP的方式解決一個稍微更加現實的問題。今年到了這個時候,讓我想起了頗具“面試”風格的計稅程序,先收集一些數據,數據不一定有什么特別的順序,最后使用所有這些數據進行一個計算。讓我們為這種情況些個簡化版本的程序:

Python風格的計稅類/實例

  1. class TaxCalc:  
  2.     def taxdue(self):return (self.income-self.deduct)*self.rate  
  3. taxclass = TaxCalc()  
  4. taxclass.income = 50000 
  5. taxclass.rate = 0.30 
  6. taxclass.deduct = 10000 
  7. print"Pythonic OOP taxes due =", taxclass.taxdue() 

在我們的TaxCalc類 (或者更準確的講,在它的實例中),我們先收集了一些數據,數據的順序隨心所欲,然后所有需要的數據收集完成后,我們可以調用這個對象的一個方法,對這堆數據進行計算。所有的一切都呆在一個實例中,而且,不同的實例可以擁有一堆不同的數據。能夠創建多個實例,而多個實例僅僅是數據不同,這通過“全局變量”和“凍結變量”這兩種方法是無法辦到的。"貨船"方法能夠做到這一點,但從那個展開的例子中我們能夠看出,它可能不得不在開始時就傳遞多個數值。討論到這里,注意到OOP風格的消息傳遞方式可能會如何來解決這一問題會非常有趣(Smalltalk或者Self與此類似,我所用過的好幾種xBase的變種OOP語言也是類似的):

Smalltalk風格的(Python) 計稅程序

  1. class TaxCalc:  
  2.     def taxdue(self):return (self.income-self.deduct)*self.rate  
  3.     def setIncome(self,income):  
  4.         self.income = income  
  5.         return self 
  6.     def setDeduct(self,deduct):  
  7.         self.deduct = deduct  
  8.         return self 
  9.     def setRate(self,rate):  
  10.         self.rate = rate  
  11.         return self 
  12. print"Smalltalk-style taxes due =", \  
  13.       TaxCalc().setIncome(50000).setRate(0.30).setDeduct(10000).taxdue() 

每個"setter"方法都返回self可以讓我們將每個方法調用的結果當作“當前”對象進行處理。這和FP中的閉包方式有些相似。

通過使用Xoltar toolkit,我們可以生成完整的閉包,能夠將數據和函數結合起來,獲得我們所需的特性;另外還可以讓多個閉包(以前成為對象)包含不同的數據: 

Python的函數式風格的計稅程序

  1. from functional import *  
  2.  
  3. taxdue        = lambda: (income-deduct)*rate  
  4. incomeClosure = lambda income,taxdue: closure(taxdue)  
  5. deductClosure = lambda deduct,taxdue: closure(taxdue)  
  6. rateClosure   = lambda rate,taxdue: closure(taxdue)  
  7.  
  8. taxFP = taxdue  
  9. taxFP = incomeClosure(50000,taxFP)  
  10. taxFP = rateClosure(0.30,taxFP)  
  11. taxFP = deductClosure(10000,taxFP)  
  12. print"Functional taxes due =",taxFP()  
  13.  
  14. print"Lisp-style taxes due =", \  
  15.       incomeClosure(50000,  
  16.           rateClosure(0.30,  
  17.               deductClosure(10000, taxdue)))() 

我們所定義的每個閉包函數可以獲取函數定義范圍內的任意值,然后將這些值綁定到改函數對象的全局范圍之中。然而,一個函數的全局范圍并不一定就是真正的模塊全局范圍,也和不同的閉包的“全局”范圍不相同。閉包就是“將數據帶”在了身邊。

在我們的例子中,我們利用了一些特殊的函數把特定的綁定限定到了一個閉包作用范圍之中(income, deduct, rate)。要想修改設計,將任意的綁定限定在閉包之中,也非常簡單。只是為了好玩,在本例子中我們也使用了兩種稍微不同的函數式風格。第一種風格連續將多個值綁定到了閉包的作用范圍;通過允許taxFP成為可變的變量,這些“添加綁定”的代碼行可以任意順序出現。然而,如果我們想要使用tax_with_Income這樣的不可變名字,我們就需要以特定的順序來安排這幾行進行綁定的代碼,將靠前的綁定結果傳遞給下一個綁定。無論在哪種情況下,在全部所需數據都綁定進閉包范圍之后,我們就可以調用“種子”(seeded)方法了。

第二種風格在我看來,更象是Lisp(那些括號最象了)。除去美學問題,這第二種風格有兩點值得注意。第一點就是完全避免了名字綁定,變成了一個單個的表達式,連語句都沒有使用(關于為什么不使用語句很重要,請參見 P第一部分)。

第二點是閉包的“Lips”風格的用法和前文給出的“Smalltalk”風格的信息傳遞何其相似。實際上兩者都在調用taxdue()函數/方法的過程中積累了所有值(如果以這種原始的方式拿不到正確的數據,兩種方式都會出錯)。“Smalltalk”風格的方法中每一步傳遞的是一個對象,而“Lisp”風格的方法中傳遞是持續進行的。 但實際上,函數式編程和面向對象式編程兩者旗鼓相當。

尾遞歸

在本文中,我們干掉了函數式編程領域中更多的內容。剩下的要比以前(本小節的題目是個小玩笑;很不幸,這里還沒有解釋過尾遞歸的概念)少多了(或者可以證明也簡單多了?)。閱讀functional模塊中的源代碼是繼續探索FP中大量概念的一種非常好的方法。該模塊中的注釋很完備,在注釋里為模塊中的大多數方法/類提供了相關的例子。其中有很多簡化性的元函數(meta-function)本專欄里并沒有討論到的,使用這些元函數可以大大簡化對其它函數的結合(combination)和交互(interaction )的處理。對于想繼續探索函數式范型的Python程序員而言,這些絕對值得好好看看。

原文鏈接:http://www.oschina.net/translate/python-functional-programming-part2

責任編輯:張偉 來源: oschina
相關推薦

2013-03-04 09:47:08

Python函數式編程

2013-03-05 10:01:29

Python函數式編程

2016-08-11 10:34:37

Javascript函數編程

2023-12-14 15:31:43

函數式編程python編程

2022-07-07 09:03:36

Python返回函數匿名函數

2013-09-09 09:41:34

2012-09-21 09:21:44

函數式編程函數式語言編程

2022-10-31 08:02:07

Python函數式編程

2018-11-15 10:20:59

Python函數式編程編程語言

2024-09-11 16:30:55

Python函數編程

2019-01-17 10:25:56

Python編程語言程序員

2024-02-28 07:59:25

2025-03-11 10:00:20

Golang編程函數

2020-09-24 10:57:12

編程函數式前端

2016-10-31 20:46:22

函數式編程Javascript

2011-03-08 15:47:32

函數式編程

2024-02-28 08:37:28

Lambda表達式Java函數式接口

2011-08-24 09:13:40

編程

2022-09-22 08:19:26

WebFlux函數式編程

2024-04-02 08:00:00

函數式編程開發
點贊
收藏

51CTO技術棧公眾號

一级毛片在线| 中文字幕日韩精品久久| 一区二区成人| 99精品在线免费| 国产精品wwwwww| 亚洲第一二三四区| 在线国产亚洲欧美| 亚洲黄色小视频在线观看| 亚洲va国产va天堂va久久| 精品99又大又爽又硬少妇毛片| www.日韩精品| 日本高清不卡一区二区三| 成人3d精品动漫精品一二三| xvideos亚洲人网站| 91高清在线观看视频| 亚洲v中文字幕| 亚欧在线免费观看| 成人小视频在线观看| 日本一区二区久久精品| 51精产品一区一区三区| 91精品国产高清久久久久久91| 日本韩国欧美| 亚洲福利视频网站| 一级日本在线| 欧美日韩亚洲高清| 先锋在线亚洲| 亚洲国产精品av| 2018中文字幕第一页| 日韩高清一区在线| 蜜桃臀一区二区三区| 好看的日韩av电影| 亚洲最大成人在线| 成人精品亚洲| 日韩美女在线观看| 菁菁伊人国产精品| 欧美激情视频网址| 精品一区91| 亚洲综合中文字幕在线观看| eeuss在线观看| 亚洲欧美色图小说| jizz亚洲大全| 综合精品久久久| 成人网18免费网站在线| 中国色在线观看另类| 激情五月开心婷婷| www久久久久| 91精品国产乱码久久蜜臀| 欧美在线视频一二三| 高潮久久久久久久久久久久久久| xvideos成人免费中文版| 亚洲国产91视频| 久久精品电影网站| 视频二区欧美毛片免费观看| 久久99久久99精品中文字幕| 久久69av| 日韩av免费网站| 午夜精品视频一区二区三区在线看| 国产精品美女午夜av| 91精品一区二区三区综合在线爱| 国产精品果冻传媒潘| 人人超碰91尤物精品国产| wwwjizzjizzcom| 久久久午夜精品理论片中文字幕| 国产三级国产精品国产专区50| 亚洲欧美日韩国产成人精品影院| 亚洲国产资源| 欧美变态口味重另类| 精精国产xxxx视频在线野外| 中文日韩在线视频| 亚州综合一区| 国产精品 日韩| 国产一区二区免费视频| 三级a在线观看| 黑人与娇小精品av专区| 久久青青色综合| 久久夜色精品国产| 国产制服91一区二区三区制服| 一区二区三区自拍视频| 国产日韩欧美在线看| 免费成人你懂的| 日本激情视频在线播放| 日韩欧美综合在线视频| av电影一区| 国产成人短视频| 久久资源在线| aa免费在线观看| 欧美午夜无遮挡| 自拍偷自拍亚洲精品被多人伦好爽 | 91欧美精品成人综合在线观看| 一区精品久久| 福利视频免费在线观看| 一个色妞综合视频在线观看| 色婷婷视频在线观看| 欧美国产日本在线| 精品1区2区3区4区| 别急慢慢来1978如如2| 欧美午夜片在线观看| 国产精品日本一区二区不卡视频| 国产精品狼人色视频一区| 日韩在线观看一区二区| 成人午夜剧场免费观看完整版| 日韩欧美在线观看一区二区三区| 亚洲免费看片| 久久久久久国产精品一区| 国产福利亚洲| 亚洲一区二区在线免费看| 国产美女高潮在线观看| 国产精品久久久91| 国产精品性做久久久久久| 色在线免费视频| 理论片在线不卡免费观看| 亚洲一区二区动漫| 一二三四中文在线| www.久久久久| 久久精品综合| 又黄又爽的视频在线观看| 久久精品视频中文字幕| 日韩成人午夜精品| 中文字幕高清在线观看| 精品精品国产国产自在线| 噜噜爱69成人精品| 又黄又爽在线观看| 久久久久久成人精品| 国产精品综合网| av电影在线观看| 国产精品高清免费在线观看| 99久久99久久免费精品蜜臀| 粗大黑人巨茎大战欧美成人| 成人在线国产精品| 亚洲欧美另类小说| 中文字幕日韩高清在线| 亚洲 欧美 综合 另类 中字| 精品国产精品一区二区夜夜嗨| 一本精品一区二区三区| 妞干网免费视频| 欧美成人免费在线视频| 久久99热99| 日本成人不卡| 久久成人资源| 欧美伊人久久久久久午夜久久久久| 日韩人体视频| 无码少妇一区二区三区芒果| 伊人久久久久久久久久久久久| 日韩国产欧美三级| 含羞草www国产在线视频| 国产乱码精品一区二区三区卡| 亚洲大片一区二区三区| 神马日本精品| 亚洲精品午夜在线观看| 久久人人爽人人爽人人片av高请| 91在线免费视频观看| 99久久婷婷国产综合精品首页 | 国产精品一区二区性色av | 裸体一区二区三区| 毛片av在线| 精品免费国产| 欧美一区永久视频免费观看| 亚洲黄色在线| 二区三区四区高清视频在线观看| 麻豆91av| 日韩欧美美女一区二区三区| 久久久噜噜噜| 美女露胸视频在线观看| 国产精品国产三级国产专区51| 亚洲性视频网站| 久久一日本道色综合| 免费精品一区| 91九色porny视频| 国产男女猛烈无遮挡91| 欧美性猛片xxxx免费看久爱| 丝袜国产日韩另类美女| 成人性生活视频| 国产精品va无码一区二区| 免费黄色网页在线观看| 国产精品播放| 精品国产乱子伦一区| 国产激情视频一区二区在线观看| 99久久精品一区二区成人| 欧美亚洲一二三区| 久久久影视精品| 尤物视频一区二区| 自拍偷拍欧美| 色a资源在线| 亚洲美免无码中文字幕在线| 欧美xxxx14xxxxx性爽| 免费成人在线电影| 国内久久久精品| 亚洲高清免费在线| 9色国产精品| 日韩高清在线| 男人插曲女人视频免费| 亚洲一区二区三| 精品国产成人系列| 久久久久久久久久久99999| 国产成人调教视频在线观看 | 116极品美女午夜一级| 国产精品福利在线观看| 欧美一区二区在线视频| 久久影院午夜片一区| 欧美高清在线|