Iterator&generator

Iterator(迭代器)

  • 概念

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

  • 可迭代對象

    迭代器提供了一個統一的訪問集合的接口。只要是實現了iter()或getitem()方法的對象,就可以使用迭代器進行訪問。

    例子:

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

    第一種:

    # 迭代器對象實現了__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__()方法實現了對象可迭代,next()方法實現了迭代。

    第二種:

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

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

    使用list構造方法顯式地講迭代器轉化成列表。

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

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

生成器

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

  • yield

    在函數中如果出現了yield關鍵字,那么該函數就不再是普通函數,而是生成器函數。

    yield 的作用就是把一個函數變成一個 generator,帶有 yield 的函數不再是一個普通函數,Python 解釋器會將其視為一個 generator。可以用for循環遍歷相比于迭代器,生成器更加靈活。

    程序執行到yield后就會返回輸出,yield下面的代碼會在下次調用next()時運行

  • yield與return

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

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

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

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

    ?

  • 創建一個生成器

    • 簡單生成器

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

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

      range()是一個生成器

    • 遞歸生成器

    # 處理多層嵌套的數據(二維數組等等)
    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]))
    

    當函數被告知展開一個元素(元素無法展開,一個可迭代對象才能展開 ),for循環會引發一個TypeError異常。但上面的那種情況在處理元素是字符串的時候不適用。

    def flatten(nested):
        try:
            # 不要迭代類似字符串的數據對象
            try:
                nested + ''  # 當nested不是一個字符串的時候會引發一個TypeError
          except TypeError:
                pass
            else: 
                raise TypeError
          for sublist in nested:
                for element in flatten(sublist):
                    yield element
      except TypeError:
            yield nested
            
     # 下面的是可以打印出多層嵌套的數據(無論是一般數據還是字符串)
    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

        可以改變生成器內部值的方法

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

        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

        用于在生成器內引發一個異常(在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’之前。
        由于執行了g.throw(ValueError),所以會跳過所有后續的try語句,也就是說yield ‘normal value 2’不會被執行,然后進入到except語句,打印出we got ValueError here。然后再次進入到while語句部分,消耗一個yield,所以會輸出normal value。
        print(next(g)),會執行yield ‘normal value 2’語句,并停留在執行完該語句后的位置。
        g.throw(TypeError):會跳出try語句,從而print(‘here’)不會被執行,然后執行break語句,跳出while循環,然后到達程序結尾,所以跑出StopIteration異常。
        """
        
      • close

        它在yield運行處引發一個GeneratorExit異常,可以對生成器內進行代碼清理,一般講yield語句放在try/finally語句中。執行close()方法后,生成器對象就會被銷毀,不能再調用next()方法

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

        ?

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容