最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

利用Fn.py庫(kù)在Python中進(jìn)行函數(shù)式編程

 更新時(shí)間:2015年04月22日 15:37:31   作者:Alexey Kachayev  
這篇文章主要介紹了利用Fn.py庫(kù)在Python中進(jìn)行函數(shù)式編程,基于Scala中的類似風(fēng)格,需要的朋友可以參考下

盡管Python事實(shí)上并不是一門(mén)純函數(shù)式編程語(yǔ)言,但它本身是一門(mén)多范型語(yǔ)言,并給了你足夠的自由利用函數(shù)式編程的便利。函數(shù)式風(fēng)格有著各種理論與實(shí)際上的好處(你可以在Python的文檔中找到這個(gè)列表):

  •     形式上可證
  •     模塊性
  •     組合性
  •     易于調(diào)試及測(cè)試

雖然這份列表已經(jīng)描述得夠清楚了,但我還是很喜歡Michael O.Church在他的文章“函數(shù)式程序極少腐壞(Functional programs rarely rot)”中對(duì)函數(shù)式編程的優(yōu)點(diǎn)所作的描述。我在PyCon UA 2012期間的講座“Functional Programming with Python”中談?wù)摿嗽赑ython中使用函數(shù)式方式的內(nèi)容。我也提到,在你嘗試在Python中編寫(xiě)可讀同時(shí)又可維護(hù)的函數(shù)式代碼時(shí),你會(huì)很快發(fā)現(xiàn)諸多問(wèn)題。

fn.py類庫(kù)就是為了應(yīng)對(duì)這些問(wèn)題而誕生的。盡管它不可能解決所有問(wèn)題,但對(duì)于希望從函數(shù)式編程方式中獲取最大價(jià)值的開(kāi)發(fā)者而言,它是一塊“電池”,即使是在命令式方式占主導(dǎo)地位的程序中,也能夠發(fā)揮作用。那么,它里面都有些什么呢?
Scala風(fēng)格的Lambda定義

在Python中創(chuàng)建Lambda函數(shù)的語(yǔ)法非常冗長(zhǎng),來(lái)比較一下:

Python

map(lambda x: x*2, [1,2,3])

Scala

復(fù)制代碼 代碼如下:

List(1,2,3).map(_*2)

Clojure

復(fù)制代碼 代碼如下:

(map #(* % 2) '(1 2 3))

Haskell

復(fù)制代碼 代碼如下:

map (2*) [1,2,3]

受Scala的啟發(fā),F(xiàn)n.py提供了一個(gè)特別的_對(duì)象以簡(jiǎn)化Lambda語(yǔ)法。

from fn import _

assert (_ + _)(10, 5) = 15
assert list(map(_ * 2, range(5))) == [0,2,4,6,8]
assert list(filter(_ < 10, [9,10,11])) == [9]

除此之外還有許多場(chǎng)景可以使用_:所有的算術(shù)操作、屬性解析、方法調(diào)用及分片算法。如果你不確定你的函數(shù)具體會(huì)做些什么,你可以將結(jié)果打印出來(lái):

from fn import _ 

print (_ + 2) # "(x1) => (x1 + 2)" 
print (_ + _ * _) # "(x1, x2, x3) => (x1 + (x2 * x3))"

流(Stream)及無(wú)限序列的聲明

Scala風(fēng)格的惰性求值(Lazy-evaluated)流。其基本思路是:對(duì)每個(gè)新元素“按需”取值,并在所創(chuàng)建的全部迭代中共享計(jì)算出的元素值。Stream對(duì)象支持<<操作符,代表在需要時(shí)將新元素推入其中。

惰性求值流對(duì)無(wú)限序列的處理是一個(gè)強(qiáng)大的抽象。我們來(lái)看看在函數(shù)式編程語(yǔ)言中如何計(jì)算一個(gè)斐波那契序列。

Haskell

復(fù)制代碼 代碼如下:
fibs = 0 : 1 : zipWith (+) fibs (tail fibs)

Clojure

復(fù)制代碼 代碼如下:
(def fib (lazy-cat [0 1] (map + fib (rest fib))))

Scala

復(fù)制代碼 代碼如下:
def fibs: Stream[Int] =
     0 #:: 1 #:: fibs.zip(fibs.tail).map{case (a,b) => a + b}

現(xiàn)在你可以在Python中使用同樣的方式了:

from fn import Stream 
from fn.iters import take, drop, map
from operator import add

f = Stream()
fib = f << [0, 1] << map(add, f, drop(1, f))

assert list(take(10, fib)) == [0,1,1,2,3,5,8,13,21,34]
assert fib[20] == 6765
assert list(fib[30:35]) == [832040,1346269,2178309,3524578,5702887]

蹦床(Trampolines)修飾符

fn.recur.tco是一個(gè)不需要大量棧空間分配就可以處理TCO的臨時(shí)方案。讓我們先從一個(gè)遞歸階乘計(jì)算示例開(kāi)始:

def fact(n):
   if n == 0: return 1
   return n * fact(n-1)

這種方式也能工作,但實(shí)現(xiàn)非常糟糕。為什么呢?因?yàn)樗鼤?huì)遞歸式地保存之前的計(jì)算值以算出最終結(jié)果,因此消耗了大量的存儲(chǔ)空間。如果你對(duì)一個(gè)很大的n值(超過(guò)了sys.getrecursionlimit()的值)執(zhí)行這個(gè)函數(shù),CPython就會(huì)以此方式失敗中止:

>>> import sys
>>> fact(sys.getrecursionlimit() * 2)
... many many lines of stacktrace ...
RuntimeError: maximum recursion depth exceeded

這也是件好事,至少它避免了在你的代碼中產(chǎn)生嚴(yán)重錯(cuò)誤。

我們?nèi)绾蝺?yōu)化這個(gè)方案呢?答案很簡(jiǎn)單,只需改變函數(shù)以使用尾遞歸即可:

def fact(n, acc=1):
   if n == 0: return acc
   return fact(n-1, acc*n)

為什么這種方式更佳呢?因?yàn)槟悴恍枰A糁暗闹狄杂?jì)算出最終結(jié)果??梢栽赪ikipedia上查看更多尾遞歸調(diào)用優(yōu)化的內(nèi)容??墒恰璓ython的解釋器會(huì)用和之前函數(shù)相同的方式執(zhí)行這段函數(shù),結(jié)果是你沒(méi)得到任何優(yōu)化。

fn.recur.tco為你提供了一種機(jī)制,使你可以使用“蹦床”方式獲得一定的尾遞歸優(yōu)化。同樣的方式也使用在諸如Clojure語(yǔ)言中,主要思路是將函數(shù)調(diào)用序列轉(zhuǎn)換為while循環(huán)。

from fn import recur

@recur.tco 
def fact(n, acc=1):
   if n == 0: return False, acc
   return True, (n-1, acc*n)

@recur.tco是一個(gè)修飾符,能將你的函數(shù)執(zhí)行轉(zhuǎn)為while循環(huán)并檢驗(yàn)其輸出內(nèi)容:

  •     (False, result)代表運(yùn)行完畢
  •     (True, args, kwargs)代表我們要繼續(xù)調(diào)用函數(shù)并傳遞不同的參數(shù)
  •     (func, args, kwargs)代表在while循環(huán)中切換要執(zhí)行的函數(shù)

函數(shù)式風(fēng)格的錯(cuò)誤處理

假設(shè)你有一個(gè)Request類,可以按照傳入其中的參數(shù)名稱得到對(duì)應(yīng)的值。要想讓其返回值格式為全大寫(xiě)、非空并且去除頭尾空格的字符串,你需要這樣寫(xiě):

class Request(dict):
   def parameter(self, name):
     return self.get(name, None)

r = Request(testing="Fixed", empty=" ")
param = r.parameter("testing")
if param is None:
   fixed = ""
else:   
   param = param.strip()
   if len(param) == 0:
     fixed = ""
   else:
    fixed = param.upper() 

額,看上去有些古怪。用fn.monad.Option來(lái)修改你的代碼吧,它代表了可選值,每個(gè)Option實(shí)例可代表一個(gè)Full或者Empty(這點(diǎn)也受到了Scala中Option的啟發(fā))。它為你編寫(xiě)長(zhǎng)運(yùn)算序列提供了簡(jiǎn)便的方法,并且去掉除了許多if/else語(yǔ)句塊。

from operator import methodcaller
from fn.monad import optionable

class Request(dict):
   @optionable
   def parameter(self, name):
     return self.get(name, None)

r = Request(testing="Fixed", empty=" ")
fixed = r.parameter("testing") 
     .map(methodcaller("strip")) 
     .filter(len) 
     .map(methodcaller("upper")) 
     .get_or("")

fn.monad.Option.or_call是個(gè)便利的方法,它允許你進(jìn)行多次調(diào)用嘗試以完成計(jì)算。例如,你有一個(gè)Request類,它有type,mimetype和url等幾個(gè)可選屬性,你需要使用最少一個(gè)屬性值以分析它的“request類型”:

from fn.monad import Option 

request = dict(url="face.png", mimetype="PNG") 
tp = Option \ 
     .from_value(request.get("type", None)) \ # check "type" key first 
     .or_call(from_mimetype, request) \ # or.. check "mimetype" key 
     .or_call(from_extension, request) \ # or... get "url" and check extension 
     .get_or("application/undefined")

其余事項(xiàng)?

我僅僅描述了類庫(kù)的一小部分,你還能夠找到并使用以下功能:

  •     22個(gè)附加的itertools代碼段,以擴(kuò)展內(nèi)置module的功能的附加功能
  •     將Python 2和Python 3的迭代器(iterator)(如range,map及filtter等等)使用進(jìn)行了統(tǒng)一,這對(duì)使用跨版本的類庫(kù)時(shí)非常有用
  •     為函數(shù)式組合及partial函數(shù)應(yīng)用提供了簡(jiǎn)便的語(yǔ)法
  •     為使用高階函數(shù)(apply,flip等等)提供了附加的操作符

正在進(jìn)行中的工作

自從在Github上發(fā)布這個(gè)類庫(kù)以來(lái),我從社區(qū)中收到了許多審校觀點(diǎn)、意見(jiàn)和建議,以及補(bǔ)丁和修復(fù)。我也在繼續(xù)增強(qiáng)現(xiàn)有功能,并提供新的特性。近期的路線圖包括以下內(nèi)容:

  •     為使用可迭代對(duì)象(iterable),如foldl,foldr增加更多操作符
  •     更多的monad,如fn.monad.Either,以處理錯(cuò)誤記錄
  •     為大多數(shù)module提供C-accelerator
  •     為簡(jiǎn)化lambda arg1: lambda arg2:…形式而提供的curry函數(shù)的生成器
  •     更多文檔,更多測(cè)試,更多示例代碼

相關(guān)文章

  • 如何使用python請(qǐng)求傳遞csrftoken

    如何使用python請(qǐng)求傳遞csrftoken

    這篇文章主要介紹了如何使用python請(qǐng)求傳遞csrftoken問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-08-08
  • python爬蟲(chóng)模塊URL管理器模塊用法解析

    python爬蟲(chóng)模塊URL管理器模塊用法解析

    這篇文章主要介紹了python爬蟲(chóng)模塊URL管理器模塊用法解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-02-02
  • Python使用lambda表達(dá)式對(duì)字典排序操作示例

    Python使用lambda表達(dá)式對(duì)字典排序操作示例

    這篇文章主要介紹了Python使用lambda表達(dá)式對(duì)字典排序操作,結(jié)合實(shí)例形式分析了lambda表達(dá)式實(shí)現(xiàn)字典按鍵排序、按值排序、多條件排序相關(guān)操作技巧,需要的朋友可以參考下
    2019-07-07
  • 在Gnumeric下使用Python腳本操作表格的教程

    在Gnumeric下使用Python腳本操作表格的教程

    這篇文章主要介紹了在Gnumeric下使用Python腳本操作表格的教程,本文來(lái)自于IBM官方網(wǎng)站,需要的朋友可以參考下
    2015-04-04
  • Python 16進(jìn)制與中文相互轉(zhuǎn)換的實(shí)現(xiàn)方法

    Python 16進(jìn)制與中文相互轉(zhuǎn)換的實(shí)現(xiàn)方法

    今天小編就為大家分享一篇Python 16進(jìn)制與中文相互轉(zhuǎn)換的實(shí)現(xiàn)方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-07-07
  • 關(guān)于python的mmh3庫(kù)安裝以及使用詳解

    關(guān)于python的mmh3庫(kù)安裝以及使用詳解

    這篇文章主要介紹了關(guān)于python的mmh3庫(kù)安裝以及使用詳解,哈希方法主要有MD、SHA、Murmur、CityHash、MAC等幾種方法,mmh3全程murmurhash3,是一種非加密的哈希算法,常用于hadoop等分布式存儲(chǔ)情境中,需要的朋友可以參考下
    2023-07-07
  • python批量修改文件名的實(shí)現(xiàn)代碼

    python批量修改文件名的實(shí)現(xiàn)代碼

    這篇文章主要介紹了python批量修改文件名的實(shí)現(xiàn)代碼,需要的朋友可以參考下
    2014-09-09
  • python修改和新增字典中鍵值對(duì)的2種方法

    python修改和新增字典中鍵值對(duì)的2種方法

    這篇文章主要給大家介紹了關(guān)于python修改和新增字典中鍵值對(duì)的2種方法,在Python中字典是一系列鍵值對(duì),每個(gè)鍵都與一個(gè)值相關(guān)聯(lián),與鍵相關(guān)聯(lián)的值可以是數(shù)、字符串、列表乃至字典,需要的朋友可以參考下
    2023-07-07
  • Python Kivy基礎(chǔ)教程的使用

    Python Kivy基礎(chǔ)教程的使用

    本文主要介紹了Python Kivy基礎(chǔ)教程的使用,包括?Label、Button、TextInput、Image、Spinner、Checkbox?和?ToggleButton?的用法,具有一定的參考價(jià)值,感興趣的可以了解一下
    2025-04-04
  • Python 可迭代對(duì)象 iterable的具體使用

    Python 可迭代對(duì)象 iterable的具體使用

    本文主要介紹了Python可迭代對(duì)象iterable,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-08-08

最新評(píng)論

秭归县| 浙江省| 铜川市| 页游| 高唐县| 广丰县| 繁峙县| 邯郸市| 杭锦旗| 泸州市| 读书| 莆田市| 凤山县| 哈巴河县| 雷波县| 眉山市| 乌鲁木齐县| 广河县| 盱眙县| 自贡市| 沂南县| 虞城县| 龙江县| 卢龙县| 榕江县| 阿鲁科尔沁旗| 翁牛特旗| 黄山市| 依安县| 桂东县| 石首市| 昆山市| 松滋市| 右玉县| 建湖县| 新邵县| 福海县| 原平市| 宁都县| 云浮市| 赤峰市|