·python·用產生器和迭代器實現自己的xrange

來源:互聯網
上載者:User
·python·用產生器和迭代器實現自己的xrange聲明:本文由戀花蝶發表於http://blog.csdn.net/lanphaday,著作權,歡迎轉載。轉載時應保留聲明。謝謝。        用過python的朋友一定很熟悉下面這兩行代碼:>>> for i in xrange(0,10,1):              print i上面的兩行代碼是用一個迴圈列印0-9這十個數字。你也想實現像xrange這樣的可以用在for語句裡的函數(類)嗎?那跟我來吧!       首先來介紹一下python的yield語句,Yield這個單詞本身有產生、產出的意思,它的文法是:yield 運算式關於yield語句,官方manual是這樣說的:yield語句僅用以定義產生器函數,而且它只能出現在產生器函數內;在函數定義中使用yield語句的充分理由是想實現以個產生器函數而不是普通函數。當產生器函數被調用,它返回一個視作產生器的迭代器的迭代器、更通俗地說是一個產生器。產生器函數的函數體將被產生器的next方法重複調用直到產生一個異常;當yield語句被執行的時候產生器的狀態被凍結並且運算式的值返回給next()的調用者,所謂“凍結”我們可以理解成函數在這裡被儲存現場並切換了出去(如果你瞭解作業系統的進程管理的話,應該很容易理解這句話)。       嗯,太隱晦了些,看個執行個體吧。>>> def simple_xrange (num):              while(num):                     yield num                     num -= 1 >>> l = list(simple_xrange(8))>>>print l[8, 7, 6, 5, 4, 3, 2, 1]在上例中我們實現了一個簡單的xrange,產生倒序的數字系列。但還是看不出這個simple_xrange是怎麼執行的,現在我們來看看下面的實驗:>>> it = simple_xrange (8)>>> it.next()8>>> it.next()7>>> it.next()6……>>> it.next()1>>> it.next() Traceback (most recent call last): File "<pyshell#48>", line 1, in -toplevel-    it.next()StopIteration現在我們從上面的實驗中來看simple_xrange的執行過程:1、  當執行it = simple_xrange(8)時,simple_xrange返回一個產生器,即it成為一個產生器。2、  當執行it.next()時,simple_xrange的函數體被執行,當執行到yield num語句時,simple_xrange被“凍結”,然後返回num,即83、  再次執行it.next(),simple_xrange“解凍”,執行num -= 1,因為是迴圈,所以再執行while(num),這時又是執行yield num,simple_xrange被“凍結”,返回num,即74、  再一次次調用下去,直到simple_xrange的while(num)不成立,跳出迴圈,返回時next()函數拋出一個StopIteration異常,這時產生器函數就執行完結了。把上面的1234條目跟上文python manual的說法對照一下,是相互呼應的,這樣我們就理解了xrange的實現機理,從而可以利用yield語句寫出自己的xrange了。       理解了yield之後,理解另一種實現xrange的方法就容易多了,這種方法就是定義自己的迭代器。對於迭代器,python manual的說法是這樣的:python支援一種超越容器的迭代器觀念,使得使用者定義的類支援迭代。迭代器對象需要支援__iter__()和next()兩個方法,其中__iter__()返回迭代器自身,next()返回系列的下一個元素。嗯,還是通過執行個體來說吧:>>> class simple_xrange:       def __init__(self, num):              self._num = num       def __iter__(self):              return self       def next(self):              if self._num <= 0:                     raise StopIteration              tmp = self._num              self._num -= 1              return tmp >>> l = list(simple_xrange(8))>>> l[8, 7, 6, 5, 4, 3, 2, 1]哈哈,讀一下原始碼,似乎這個比yield語句更簡明易懂,也許這就是在有了yield語句之後還要支援迭代器類型的原因吧!有了yield知識,理解這段原始碼是很簡單的了,我就不多言了。       搞了這麼久,實現自己的xrange有必要嗎?當然是有的,xrange只是產生了一個系列,如果要對這個系列有什麼擴充的話,寫出來的代碼就比較難看了。舉個在現實工作中我遇到的例子:我做一個紙牌遊戲,我用list來表示將要打出的牌(我用0~53表示一副牌,其中0表示最小的牌——方塊3),如[0,0,3,3]表示兩對編號分別為0,3的牌,即由兩個方塊3兩個黑桃3組成的炸彈(本遊戲使用兩副牌,所以可以有兩個相同的牌ID)。後來修改了遊戲規則,新的遊戲規則規定大joker(牌ID為53)可以變化為任意牌,比如[0,0,3,53]也是一個炸彈。這時我寫了下面的代碼來判斷一個list是不是一個正確的牌型:#當cards裡有big joker時調用本函數判斷是否為有效牌型def is_valid_pattern_with_big_joker(cards):       _cards = cards[:]   #因為要改變cards,所以函數內使用cards的拷貝       be_replace_card = 53 #big joker將被替換       #枚舉所有的可能       for i in xrange(53, -1,-1):              _cards.remove(be_replace_card)              _cards.append(i)              be_replace_card = i              if is_valid_pattern(_cards)#如果還有big joker,is_valid_pattern會遞迴調用本函數                     return True       return False看那for迴圈的迴圈體,多麼複雜,又是remove又是append還有中間變數要儲存,有沒有辦法簡單點?有!使用迭代器吧。class ReplacedBigJokerCards:       def __init__(self, cards):              self._cards = cards[:]              self._be_replaced_card = 53              self._candidate = 52       def __iter__(self):              return self       def next(self):              if self._candidate < 0:                     raise StopIterationself._cards.remove(self._be_replace_card)self._cards.append(self._candidate)self._be_replace_card = self._candidate              self._candidate -= 1              return self._cards def is_valid_pattern_with_big_joker(cards):       for _cards in ReplacedBigJokerCards(cards):              if is_valid_pattern(_cards)                     return True       return False 看,現在把大joker變牌的細節隱藏起來,is_valid_pattern_with_big_joker變得優雅多了。重要的另一點就是在遊戲中,除了判定牌型外,還有智能提示等多個功能都能夠重用ReplaceBigJokerCards,使用這樣的定製迭代器,比散落在代碼各處的remove/append比好得多。

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.