迭代器和生成器

迭代器

  • 思惟打開:如何從列表中取值
    • for循環
    • 索引
  • 迭代器應用在可for循環的數據中,即擁有__iter__方法
    • 字符串
    • 集合
    • 列表
    • 元組
    • range()
    • f = open()
    • enumerate 枚舉
    • 字典
  • 可迭代協議
    • 只要內部含有__iter__方法都是可迭代的面試

      print(__iter__() in dir([]))
  • 迭代器協議
    • 內部含有__next__和__iter__方法都是迭代器
  • isinstance(數據, 類型) 判斷數據是不是類型
  • 迭代器協議和可迭代協議
  • 只要能被for循環的都是可迭代的
  • 可迭代的.__iter__()就是一個迭代器
  • 迭代器中的__next__()方法就是一個一個的獲取值app

    迭代器的優勢

  • 迭代器能夠自定取元素
  • 節省內存空間函數

    #模仿for循環獲取列表的元素
          l = [1, 2, 3, 4, 5]
          iterator = l.__iter__()
          while 1:
              try:
                  print(iterator.__next__())
              except:
                  break

    實際例子

  • 實際告訴你這是個迭代器
  • 可迭代對象
  • 直接給你內存地址線程

    用for的狀況

  • 只有內部有__iter__()方法的數據才能用for循環指針

生成器 -一個迭代器

  • 本質也是迭代器
  • 生成器能夠記住本身已經迭代到哪兒了
  • 迭代器不能記住本身迭代到哪兒了code

    生成器函數

  • 本質上就是咱們本身寫的函數
  • 只要含有yield就是生成器函數
  • 函數yieldreturn不能共用
  • yield只能在函數裏用
  • 生成器函數執行以後會產生一個生成器做爲返回值對象

    #普通函數
          def func():
              print(1)
              return 'a'
          #調用
          ret = func()
          print(ret)
          #結果
          1
          a
    
          #生成器函數
          def generator():
              print(1)
              yield 'a'
          #調用
          ret = generator()
          print(ret)
          #結果
          <generator object generator at 0x000000000> #返回的是一個內存地址
          #換種方式調用
          ret = generator()
          print(ret.__next__())
          #結果
          1
          a
  • yield不會像return同樣結束函數
  • yield也會返回一個值
  • 每調用一個__next__()就會輸出一個yield返回的值索引

    #定義一個生成器函數
          def generator():
          for i in range(100):
              yield i
    
          g1 = generator()    
          g2 = generator()
    
          #循環打印生成器函數內容
          while 1:
              try:
                  print(g1.__next__())
                  print(g2.__next__())
              except:
                  break
         #結果是同步運行,因此至關於雙線程

    生成器函數進階

  • yield後再也不有函數體了內存

    def wrapper():
              print(1)
              yield 8
              print(2)
              yield 8
              print(2)    #後方沒有yield能夠打印可是報錯
  • __next__()send效果能夠一致
    • 獲取下一個值的效果一致
  • 可是也有不一樣,send()可以傳值
    • 只不過獲取下一個值的時候給上一個yield傳一個值
  • send使用注意事項
    1. 第一個值必須用__next__()調取
    2. 最後一個yield不能接收外部的值字符串

      #send()不傳入參數
       def wrapper():
           print('=')
           yield '第一個'
           print('==')
           yield '第二個'
       #調用
       g = wrapper()
       print(g.__next__())
       print(g.send(None)) 
       #結果
       =
       第一個
       ==
       第二個
      
       #send傳入任意參數,如'hello'
       def wrapper():
           print('=')
           countent = yield '第一個'  #這裏給yield賦值countent
           print('~~', countent)   #這裏添加一個打印信息
           print('==')
           yield '第二個'
       #調用
       g = wrapper()
       print(g.__next__()) #第一個值的調取必須用__next__()
       print(g.send(hello))    
       #結果
       =
       第一個
       ~~ hello    #這裏結果出現了hello說明參數傳進去了
       ==
       第二個

      練習應用

  • 一個計算戰績平均值的應用

    #生成器函數,用來計算戰績平均值
          def averge():
              count = 0
              aver = 0
              num = 0
              add = 0
              while 1:
                  num = yield
                  add += num
                  count += 1
                  aver = add/count
                  yield aver
    
          #持續輸入的函數,用來輸入每局成績
          def print_num():
              g = averge()
              while 1:
                  num = int(input('輸入:'))
                  g.__next__()
                  print(g.send(num))
    
          print_num()
  • 將上面的做業改爲裝飾器形式
    • 預激活裝飾器

      #裝飾器做爲持續輸入的函數
        #裝飾器爲生成器函數提供用戶輸入
        def print_num(func):
            def inner(*args, **kwargs):
                g = func(*args, **kwargs)
                while 1:
                    num = int(input('輸入:'))
                    g.__next__()
                    print(g.send(num))
                return g
            return inner
      
        #生成器函數
        @print_num
        def averge():
            count = 0
            aver = 0
            num = 0
            add = 0
            while 1:
                num = yield
                add += num
                count += 1
                aver = add/count
                yield aver
        #調用
        averge()
  • yield from用法

    def generator():
              a = '12345'
              b = 'abcde'
              yield from a
              yield from b
          #調用
          g = generator()
          for i in g:
              print(i)
          #結果
          1
          2
          3
          4
          5
          a
          b
          c
          d
          e

生成器表達式

列表推導式

list = [i for i in rang(10)]
#獲得的結果
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

生成器表達式

g = (i for i in range(10))  #生成器
print(g)
#結果
<generator object <xxx> at 0x0000000>   #一個內存地址
#利用for循環獲取生成器裏的元素
for i in g:
    print(i)
#結果
0
1
2
3
4
5
6
7
8
9
  • 生成器表達式和列表推倒式區別
    • 返回值不同
    • 括號不同
    • 兩者優缺點
      • 列表推倒式代碼量少,觀看直觀,可是佔內存
      • 生成器表達式幾乎不佔用內存可是使用起來代碼量多,觀看不直觀

經典面試題

  • 生成器是一個有指針的數據類型,所以循環一遍以後指針在數據以後,沒法再繼續取值

    #定義一個生成器函數
      def generator():
          for i in range(6)
              yield i
    
      g = generator() #生成器
      g1 = (i for i in g)
      g2 = (i for i in g1)
    
      print(list(g1))
      print(list(g2))
      #結果
      [0, 1, 2, 3, 4, 5]
      []
相關文章
相關標籤/搜索