Iterator&generator

Iterator(迭代器)

  • 概念

    迭代器是訪問集合元素的一種方式勿璃。迭代器對象從集合的第一個元素開始訪問扎酷,直到所有的元素被訪問完結(jié)束。迭代器只能往前不會后退颈畸。

  • 可迭代對象

    迭代器提供了一個統(tǒng)一的訪問集合的接口伞访。只要是實現(xiàn)了iter()或getitem()方法的對象掂骏,就可以使用迭代器進行訪問轰驳。

    例子:

    • 序列:字符串厚掷、列表、元組
    • 非序列:字典级解、文件
    • 自定義類:用戶自定義的類實現(xiàn)了iter()或getitem()方法的對象
  • 可迭代對象創(chuàng)建的兩種方法

    第一種:

    # 迭代器對象實現(xiàn)了__iter__()方法
    class Fibs:
      def __init__(self):
            self.a = 0
            self.b = 0
        def next(self):
            self.a,self.b = self.b,self.a+self.b
            return self.a
          def __iter__(self):
            return self
    

    __iter__()方法實現(xiàn)了對象可迭代冒黑,next()方法實現(xiàn)了迭代。

    第二種:

    # 用iter()工廠類實例化一個可迭代對象
    it = iter([1,2,3])
    it.next()
    
  • 從迭代器中獲得序列

    it = iter([1,23,3])
    lits(it)
    

    使用list構(gòu)造方法顯式地講迭代器轉(zhuǎn)化成列表勤哗。

  • 一種更方便的建立迭代器

    # 用括號擴住才是迭代器
    it = (x for x in [2,3,4])
    
    

生成器

  • 概念
    生成器是一種用普通的函數(shù)語法定義的迭代器(也叫簡單生成器)抡爹,有點像java中的靜態(tài)域里面的數(shù)據(jù),但用更加靈活芒划。生成器不會把結(jié)果保存在一個系列中冬竟,而是保存生成器的狀態(tài),在每次進行迭代時返回一個值民逼,直到遇到StopIteration異常結(jié)束泵殴。

  • yield

    在函數(shù)中如果出現(xiàn)了yield關(guān)鍵字,那么該函數(shù)就不再是普通函數(shù)拼苍,而是生成器函數(shù)笑诅。

    yield 的作用就是把一個函數(shù)變成一個 generator,帶有 yield 的函數(shù)不再是一個普通函數(shù),Python 解釋器會將其視為一個 generator吆你∠乙叮可以用for循環(huán)遍歷相比于迭代器,生成器更加靈活妇多。

    程序執(zhí)行到y(tǒng)ield后就會返回輸出伤哺,yield下面的代碼會在下次調(diào)用next()時運行

  • yield與return

    在一個生成器中,如果沒有return默责,則默認執(zhí)行到函數(shù)完畢時返回StopIteration
    如果遇到return,如果在執(zhí)行過程中 return,則直接拋出 StopIteration 終止迭代桃序。

    # 不會執(zhí)行到'b'
    def ge():
      yield 'a'
        return 
      yield 'b'  
    

    如果在return后返回一個值烂瘫,那么這個值為StopIteration異常的說明媒熊,不是程序的返回值。

    # 不會輸出'world'
    def ge():
      yield 'hello'
        return 'world'
    

    ?

  • 創(chuàng)建一個生成器

    • 簡單生成器

      # 簡單生成器坟比,一個無窮產(chǎn)生奇數(shù)的生成器函數(shù)
      def odd():
          n=1
          while True:
              yield n
              n+=2
      
      
    • 循環(huán)生成器

      # 循環(huán)生成器
      g = ((i+2)**2 for i in range(2, 27))
      

      range()是一個生成器

    • 遞歸生成器

    # 處理多層嵌套的數(shù)據(jù)(二維數(shù)組等等)
    def flatten(nested):
        try:
            for sublist in nested:
                forelement in flatten(sublist):
                    yield element
      except TypeError:
            yield nested
    list(flatten([1,[2,3],[4,[5,6]],7,8]))
    

    當(dāng)函數(shù)被告知展開一個元素(元素?zé)o法展開,一個可迭代對象才能展開「鹫恕),for循環(huán)會引發(fā)一個TypeError異常籍琳。但上面的那種情況在處理元素是字符串的時候不適用菲宴。

    def flatten(nested):
        try:
            # 不要迭代類似字符串的數(shù)據(jù)對象
            try:
                nested + ''  # 當(dāng)nested不是一個字符串的時候會引發(fā)一個TypeError
          except TypeError:
                pass
            else: 
                raise TypeError
          for sublist in nested:
                for element in flatten(sublist):
                    yield element
      except TypeError:
            yield nested
            
     # 下面的是可以打印出多層嵌套的數(shù)據(jù)(無論是一般數(shù)據(jù)還是字符串)
    def flatten(nested):
        try:
            if isinstance(nested, str):
                raise TypeError
            for sublist in nested:
                for element in sublist:
                    yield element
        except TypeError:
            yield nested
            
    

    ?

    • 生成器方法

      • send

        可以改變生成器內(nèi)部值的方法

        要在生成器掛起后才有意義(也就是說在yield函數(shù)第一次被運行之后),如果相對剛剛啟動的生成器使用send()方法趋急,可以講None作為其參數(shù)進行調(diào)用。

        def repeater(value):
          while True:
          new = (yield value)
          if new is not None:
          value = new 
        # 使用方法
        r = repeater(42)
        r.next()
        r.send('Hello world!')
        
      • throw

        用于在生成器內(nèi)引發(fā)一個異常(在yield表達式中)

        def gen():
          while True:
              try:
                  yield 'normal value'
                  yield 'normal value 2'
                  print 'here'
              except ValueError:
                  print 'we got ValueError here'
              except TypeError:
                  break
        # gen()用法
        g - gen()
        print next(g)
        print g.throw(Valueerror)
        print next(g)
        print g.throw(TypeError)
        
        """
        程序的輸出:
        print(next(g)):會輸出normal value谣蠢,并停留在yield ‘normal value 2’之前。
        由于執(zhí)行了g.throw(ValueError)眉踱,所以會跳過所有后續(xù)的try語句霜威,也就是說yield ‘normal value 2’不會被執(zhí)行,然后進入到except語句侥祭,打印出we got ValueError here茄厘。然后再次進入到while語句部分谈宛,消耗一個yield,所以會輸出normal value吆录。
        print(next(g)),會執(zhí)行yield ‘normal value 2’語句哀卫,并停留在執(zhí)行完該語句后的位置。
        g.throw(TypeError):會跳出try語句此改,從而print(‘here’)不會被執(zhí)行侄柔,然后執(zhí)行break語句,跳出while循環(huán)暂题,然后到達程序結(jié)尾,所以跑出StopIteration異常纵苛。
        """
        
      • close

        它在yield運行處引發(fā)一個GeneratorExit異常,可以對生成器內(nèi)進行代碼清理言津,一般講yield語句放在try/finally語句中。執(zhí)行close()方法后贝椿,生成器對象就會被銷毀陷谱,不能再調(diào)用next()方法

        def gen():
          yield 1
          yield 2
          yield 3
          
        g = gen()
        print next(g)
        g.close()
        next(g)
        

        ?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末瑟蜈,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子宪躯,更是在濱河造成了極大的恐慌位迂,老刑警劉巖访雪,帶你破解...
    沈念sama閱讀 218,546評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件臣缀,死亡現(xiàn)場離奇詭異,居然都是意外死亡精置,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評論 3 395
  • 文/潘曉璐 我一進店門番宁,熙熙樓的掌柜王于貴愁眉苦臉地迎上來赖阻,“玉大人,你說我怎么就攤上這事火欧。” “怎么了离陶?”我有些...
    開封第一講書人閱讀 164,911評論 0 354
  • 文/不壞的土叔 我叫張陵衅檀,是天一觀的道長。 經(jīng)常有香客問我沉眶,道長杉适,這世上最難降的妖魔是什么谎倔? 我笑而不...
    開封第一講書人閱讀 58,737評論 1 294
  • 正文 為了忘掉前任片习,我火速辦了婚禮蹬叭,結(jié)果婚禮上藕咏,老公的妹妹穿的比我還像新娘秽五。我一直安慰自己,他們只是感情好盲再,可當(dāng)我...
    茶點故事閱讀 67,753評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著贷揽,像睡著了一般绿映。 火紅的嫁衣襯著肌膚如雪擒滑。 梳的紋絲不亂的頭發(fā)上叉弦,一...
    開封第一講書人閱讀 51,598評論 1 305
  • 那天淹冰,我揣著相機與錄音,去河邊找鬼樱拴。 笑死,一個胖子當(dāng)著我的面吹牛晶乔,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播阵漏,決...
    沈念sama閱讀 40,338評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼翻具,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了裆泳?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,249評論 0 276
  • 序言:老撾萬榮一對情侶失蹤运提,失蹤者是張志新(化名)和其女友劉穎帜篇,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,696評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡坎缭,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,888評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了坏快。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,013評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡昧旨,死狀恐怖祥得,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情级及,我是刑警寧澤,帶...
    沈念sama閱讀 35,731評論 5 346
  • 正文 年R本政府宣布怕吴,位于F島的核電站县踢,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏硼啤。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,348評論 3 330
  • 文/蒙蒙 一爸业、第九天 我趴在偏房一處隱蔽的房頂上張望亏镰。 院中可真熱鬧,春花似錦索抓、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,929評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽大刊。三九已至三椿,卻和暖如春葫辐,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背耿战。 一陣腳步聲響...
    開封第一講書人閱讀 33,048評論 1 270
  • 我被黑心中介騙來泰國打工焊傅, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人狐胎。 一個月前我還...
    沈念sama閱讀 48,203評論 3 370
  • 正文 我出身青樓顽爹,卻偏偏與公主長得像纤泵,于是被迫代替她去往敵國和親镜粤。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,960評論 2 355

推薦閱讀更多精彩內(nèi)容