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

在Python中使用itertools模塊中的組合函數(shù)的教程

系統(tǒng) 1750 0

理解新概念

Python V2.2 中引入了迭代器的思想。唔,這并不十分正確;這種思想的“苗頭”早已出現(xiàn)在較老的函數(shù) xrange() 以及文件方法 .xreadlines() 中了。通過引入 yield 關鍵字,Python 2.2 在內部實現(xiàn)的許多方面推廣了這一概念,并使編程定制迭代器變得更為簡單( yield 的出現(xiàn)使函數(shù)轉換成生成器,而生成器反過來又返回迭代器)。

迭代器背后的動機有兩方面。將數(shù)據(jù)作為序列處理通常是最簡單的方法,而以線性順序處理的序列通常并不需要都同時實際 存在。

x*() 前兆提供了這些原理的清晰示例。如果您想對某操作執(zhí)行成千上萬次,那么執(zhí)行您的程序可能要花些時間,但該程序一般不需要占用大量內存。同樣,對于許多類型的文件,可以一行一行地處理,且不需要將整個文件存儲在內存中。最好對其它所有種類的序列也進行惰性處理;它們可能依賴于通過通道逐步到達的數(shù)據(jù),或者依賴于一步一步執(zhí)行的計算。

大多數(shù)時候,迭代器用在 for 循環(huán)內,就象真正的序列那樣。迭代器提供了 .next() 方法,它可以被顯式調用,但有百分之九十九的可能,您所看到的是以下行:

            
for x in iterator:
  do_something_with(x)


          

在對 iterator.next() 進行幕后調用而產(chǎn)生 StopIteration 異常時,該循環(huán)就被終止。順便說一下,通過調用 iter(seq) ,實際序列可以被轉換成迭代器 - 這不會節(jié)省任何內存,但是在下面討論的函數(shù)中它會很有用。

Python 不斷發(fā)展的分裂性格

Python 對函數(shù)編程(FP)的觀點有點相互矛盾。一方面,許多 Python 開發(fā)人員輕視傳統(tǒng)的 FP 函數(shù) map() 、 filter() 和 reduce() ,常常建議使用“列表理解”來代替它們。但完整的 itertools 模塊恰恰是由與這些函數(shù)類型完全相同的函數(shù)組成的,只不過這些函數(shù)對“惰性序列”(迭代器)操作,而不是對完整的序列(列表,元組)操作。而且,Python 2.3 中沒有任何“迭代器理解”的語法,這似乎與列表理解擁有一樣的動機。

我猜想 Python 最終會產(chǎn)生某種形式的迭代器理解,但這取決于找到合適于它們的自然語法。同時,在 itertools 模塊中,我們擁有大量有用的組合函數(shù)。大致地,這些函數(shù)中的每一個都接受一些參數(shù)(通常包含一些基礎迭代器)并返回一個新迭代器。例如,函數(shù) ifilter() 、 imap() 和 izip() 都分別直接等同于缺少詞首 i 的內置函數(shù)。

缺少的等價函數(shù)

itertools 中沒有 ireduce() ,盡管按道理很自然地應該有這個函數(shù);可能的 Python 實現(xiàn)是:
清單 1. ireduce() 的樣本實現(xiàn)

            
def ireduce(func, iterable, init=None):
  if init is None:
    iterable = iter(iterable)
    curr = iterable.next()
  else:
    curr = init
  for x in iterable:
    curr = func(curr, x)
    yield curr


          

ireduce() 的用例類似于 reduce() 的用例。例如,假設您想要添加某個大型文件所包含的一列數(shù)字,但是當滿足一個條件時就停止。您可以使用以下代碼來監(jiān)控正在計算的合計數(shù):
清單 2. 添加并合計一列數(shù)

            
from operator import add
from itertools import *
nums = open('numbers')
for tot in takewhile(condition, ireduce(add, imap(int, nums)):
  print "total =", tot


          

一個更實際的示例可能類似于將事件流應用于有狀態(tài)對象上,例如應用到 GUI 窗口小部件上。但是即使是上述簡單示例也顯示了迭代器組合器的 FP 風格。

基本迭代器工廠

itertools 中的所有函數(shù)都可以用純 Python 輕松地實現(xiàn)為生成器。在 Python 2.3+ 中包含該模塊的要點是為一些有用的函數(shù)提供標準行為和名稱。盡管程序員可以編寫他們自己的版本,但是每個人實際創(chuàng)建的變體都會有點不兼容。但是,另一方面是要以高效率的 C 代碼實現(xiàn)迭代器組合器。使用 itertools 函數(shù)將比編寫您自己的組合器稍微快一些。標準文檔顯示了每個 itertools 函數(shù)的等價純 Python 實現(xiàn),所以不需要在本文中重復這些內容了。

itertools 中的函數(shù)再基本不過了 - 而且命名也完全不同 - 這樣從該模塊導入所有名稱可能就有意義了。例如,函數(shù) enumerate() 可能明顯地出現(xiàn)在 itertools 中,但是它在 Python 2.3+ 中卻是一個內置函數(shù)。值得注意的是,您可以用 itertools 函數(shù)很方便地表達 enumerate() :

            
from itertools import *
enumerate = lambda iterable: izip(count(), iterable)


          

讓我們首先看一下幾個 itertools 函數(shù),它們 沒有將其它迭代器作為基礎,而完全是“從頭”創(chuàng)建迭代器。 times() 返回一個多次產(chǎn)生同一對象的迭代器;在本質上,這一能力比較有用,但它確實可以很好地替代使用過多的 xrange() 和索引變量,從而可以簡單地重復一個操作。即,不必使用:

            
for i in xrange(1000):
  do_something()


          

您現(xiàn)在就可以使用更中性的:

            
for _ in times(1000):
  do_something()


          

如果 times() 只有一個參數(shù),那么它只會重復產(chǎn)生 None 。函數(shù) repeat() 類似于 times() ,但它無界地返回同一對象。不管是在包含獨立 break 條件的循環(huán)中還是在象 izip() 和 imap() 這樣的組合器中,這個迭代器都很有用。

函數(shù) count() 有點類似于 repeat() 和 xrange() 的交叉。 count() 無界地返回連續(xù)整數(shù)(以可選的參數(shù)為開始)。但是,如果 count() 當前不支持溢出到現(xiàn)在正確的 longs,那么您可能還是要使用 xrange(n,sys.maxint) ;它并不是完全無界的,但是對于大多數(shù)用途,它實際上是一回事。類似于 repeat() , count() 在其它迭代器組合器內部特別有用。

組合函數(shù)

我們已經(jīng)順便提到了 itertools 中的幾個實際組合函數(shù)。 ifilter() 、 izip() 和 imap() 的作用就象您會期望從它們相應的序列函數(shù)上獲得的作用。 ifilterfalse() 很方便,所以您不需要去掉 lambda 和 def 中的謂詞函數(shù)(而且這還節(jié)省了大量的函數(shù)調用開銷)。但是在功能上,您可以將 ifilterfalse() 定義為(大致的情況,忽略了 None 謂詞):

            
def ifilterfalse(predicate, iterable):
  return ifilter(lambda predicate: not predicate, iterable)


          

函數(shù) dropwhile() 和函數(shù) takewhile() 根據(jù)謂詞對迭代器進行劃分。 dropwhile() 在直到滿足某個謂詞 之前忽略所產(chǎn)生的元素, takewhile() 在滿足某個謂詞 時就終止。 dropwhile() 跳過迭代器的不定數(shù)目的初始元素,所以它可能直到某個延遲后才開始迭代。 takewhile() 馬上開始迭代,但是如果被傳入的謂詞變?yōu)檎妫敲淳徒K止迭代器。

函數(shù) islice() 基本上就是列表分片的迭代器版本。您可以指定開始、停止和步長,就象使用常規(guī)的片。如果給定了開始,那么會刪除大量元素,直到被傳遞的迭代器到達滿足條件的元素為止。這是另一個我認為可以對 Python 進行改進的情形 - 迭代器最好只識別片,就象列表所做的(作為 islice() 行為的同義詞)。

最后一個函數(shù) starmap() 在 imap() 基礎上略微有些變化。如果這個作為參數(shù)傳遞的函數(shù)獲取多個參數(shù),那么被傳遞的 iterable 會產(chǎn)生大小適合的元組。這基本上與包含多個被傳入 iterable 的 imap() 相同,只不過它包含先前與 izip() 結合在一起的 iterables 集合。

深入探討

itertools 中包含的函數(shù)是一個很好的開始。不使用其它函數(shù),只用這些函數(shù)就可以讓 Python 程序員更輕松地利用和組合迭代器。一般說來,迭代器的廣泛使用對 Python 的未來無疑是很重要的。但是除了過去所包含的內容以外,我還要對該模塊的將來更新提幾點建議。您可以立即很方便地使用這些函數(shù) - 當然,如果它們是后來被包含進來的,那么名稱或接口細節(jié)會有所不同。

一種可能會很通用的類別是一些將多個 iterable 作為參數(shù),隨后從每個 iterable 產(chǎn)生單獨元素的函數(shù)。與此相對照的是, izip() 產(chǎn)生元素元組,而 imap() 產(chǎn)生從基本元素計算而來的值。我頭腦中很清晰的兩個安排是 chain() 和 weave() 。第一個在效果上類似于序列并置(但是有點惰性)。即,在您可能使用的純序列中,例如:

            
for x in ('a','b','c') + (1, 2, 3):
  do_something(x)


          

對于一般的 iterables,您可以使用:

            
for x in chain(iter1, iter2, iter3):
  do_something(x)


          

Python 實現(xiàn)是:
清單 3. chain() 的樣本實現(xiàn)

            
def chain(*iterables):
  for iterable in iterables:
    for item in iterable:
      yield item


          

使用 iterables,您還可以通過使它們分散排列來組合幾個序列。還沒有任何對序列執(zhí)行這樣相同操作的內置語法,但是 weave() 本身也非常適用于完整的序列。下面是可能的實現(xiàn)(Magnus Lie Hetland 提出了 comp.lang.python 的類似函數(shù)):
清單 4. weave() 的樣本實現(xiàn)

            
def weave(*iterables):
  "Intersperse several iterables, until all are exhausted"
  iterables = map(iter, iterables)
  while iterables:
    for i, it in enumerate(iterables):
      try:
        yield it.next()
      except StopIteration:
        del iterables[i]


          

讓我來演示一下 weave() 的行為,因為從實現(xiàn)上看不是很明顯:

            
>>> for x in weave('abc', xrange(4), [10,11,12,13,14]):
...  print x,
...
a 0 10 b 1 11 c 2 12 13 3 14


          

即使一些迭代器到達終點,但其余迭代器會繼續(xù)產(chǎn)生值,直到在某一時刻產(chǎn)生了所有可用的值為止。

我將另外只提出一個可行的 itertools 函數(shù)。提出這個函數(shù)主要是受到了構思問題的函數(shù)編程方法的啟發(fā)。 icompose() 與上面提出的函數(shù) ireduce() 存在某種對稱。但是在 ireduce() 將值的(惰性)序列傳遞給某個函數(shù)并產(chǎn)生每個結果的地方, icompose() 將函數(shù)序列應用于每個前趨函數(shù)的返回值。可以把 ireduce() 用于將事件序列傳遞給長期活動的對象。而 icompose() 可能將對象重復地傳遞給返回新對象的賦值函數(shù)。第一種方法是相當傳統(tǒng)的考慮事件的 OOP 方法,而第二種的思路更接近于 FP。

以下是可能的 icompose() 實現(xiàn):
清單 5. icompose() 的樣本實現(xiàn)

            
def icompose(functions, initval):
  currval = initval
  for f in functions:
    currval = f(currval)
    yield currval


          

結束語

迭代器 - 被認為是惰性序列 - 是功能強大的概念,它開啟了 Python 編程的新樣式。但是在只把迭代器當作數(shù)據(jù)源與把它作為一種序列來考慮之間存在著微妙的差別。這兩種想法本質上哪一種都不見得比另一種更正確,但是后者開創(chuàng)了操作編程事件的一種組合性的簡略表達方法。 itertools 中的組合函數(shù)(尤其是它可能產(chǎn)生的一些類似于我建議的函數(shù))接近于編程的聲明樣式。對我而言,這些聲明樣式一般都更不易出錯且更強大。


更多文章、技術交流、商務合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯(lián)系: 360901061

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

【本文對您有幫助就好】

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

發(fā)表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 久久午夜一区二区 | 一本清高清dvd日本播放器 | 手机观看毛片 | 精品国产中文字幕 | 亚洲国产精品久久久久网站 | 四虎精品免费久久 | 欧美日韩中文字幕 | 亚洲精品乱码久久久久久蜜桃欧美 | 亚洲欧美乱综合图片区小说区 | 色婷婷综合网 | 特级毛片免费播放 | 色偷偷亚洲天堂 | 男人搡女人视频免费看 | 中文字幕一区二区视频 | 亚洲在线视频播放 | 日韩中文字幕在线有码视频网 | 免费一看一级毛片 | 国产精品成人一区二区不卡 | 成人免费a视频 | 亚洲日韩第一页 | 日韩欧美二区在线观看 | 欧美一级爱操视频 | 在线观看国产一区二区三区99 | 天天躁日日2018躁狠狠躁 | 久久久精品国产免费观看同学 | 欧洲a老妇女黄大片 | 青青爽国产手机在线观看免费 | 97人人在线视频 | 狠狠影视 | 人人爱操| 国产精品久久久久久久小唯西川 | 亚洲成人免费观看 | 大香伊人久久 | 亚洲天堂资源 | 亚洲国产精品欧美综合 | 玖玖福利 | 九九香蕉 | 亚洲色欧美 | 99免费在线观看视频 | 欧美一区二区在线 | aaa级精品久久久国产片 |