生成器

當列表包含很是多元素時,會佔用大量存儲空間,而若是僅需訪問前面幾個元素,則後面絕大多數元素佔用的空間都被浪費了
若是列表元素能夠按照某種算法推算出來,則能夠在循環的過程當中不斷推算出後續的元素,這樣就沒必要建立完整的list,從而節省大量的空間

在Python中,這種一邊循環一邊計算的機制,稱爲生成器(generator)
經過定義可知,generator保存的不是數據,而是得到元素的算法

建立生成器有兩種方式
  1) 簡單地把列表生成式改爲generator,就是建立列表時,將[]修改成()
  2) 經過函數實現複雜邏輯的generator,函數體內使用yield語句
算法

生成器工做原理
  當使用for循環時,在for循環的過程當中不斷計算出下一個元素,並在適當的條件結束for循環
  當使用next()時,調用一次next,生成器計算出下一個元素,只到生成器沒法計算出下一個值並報Iteration錯誤函數

生成器與普通函數區別
  普通函數:每調用一次,都會從函數體第一行代碼開始執行,直到最後遇到return語句或最後一行,返回結果
  生成器函數:每調用一次,第一次執行會從函數第一行代碼開始執行,遇到yield語句返回,後續代碼不會執行
        當再次調用時,會接着上次執行的yield語句後開始執行,直到遇到下一個yield語句返回,後續代碼不會執行
        以此類推,直到遇到最後一個yield語句並返回
        此時,若是使用的是for循環迭代的,則生成器正常結束,若是使用的是next()迭代的,會報錯
           實際上生成器返回的是一個generator對象spa

使用示例:
  建立列表方式建立生成器code

  L = [x * x for x in range(10)]
  g = (x * x for x in range(10))  #建立列表和生成器的區別僅在於最外層的[]和(),L是一個list,而g是一個generator

 

  next()迭代生成器對象

  next(g)  #輸出:0
  next(g)  #輸出:1
  next(g)  #輸出:4
  next(g)  #輸出:9
  ...
  next(g)  #輸出:StopIteration,
  #generator保存的是算法,每次調用next(g),generator就計算出下一個元素的值,直到最後一個元素,沒有更多的元素時,拋出StopIteration的錯誤

 

  for循環迭代生成器blog

  g = (x * x for x in range(10))
  for n in g:
    print(n) 
  #for循環體內沒有調用next方法,所以不用擔憂報StopIteration錯誤
  #函數變成generator後,基本上不會用next()來獲取下一個返回值,而是直接使用for循環來迭代

 

  函數實現生成器
  若是一個函數定義中包含yield關鍵字,那麼這個函數就再也不是一個普通函數,而是一個generatorgenerator

  def odd():  #odd不是普通函數,而是generator
    yield 1
    yield 3
    yield 5

  o = odd() #調用該generator時,首先要生成一個generator對象,而後用next()函數不斷得到下一個返回值
  next(o) #輸出:1,第1次調用next,執行odd()函數的yield 1並返回1,後面的yield 3和yield 5不執行
  next(o) #輸出:2,第2次調用next,直接執行odd()函數的yield 3,後面的yield 5不執行,並返回2
  next(o) #輸出:3,第3次調用next,直接執行odd()函數的yield 5,並返回5
  next(o) #輸出:報StopIteration錯誤,第4次調用next,發現odd()函數沒有其餘yield值,並報StopIteration錯誤

 

  斐波那契數列實現
    生成器函數定義io

  def fib(max):
    n, a, b = 0, 0, 1
    while n < max: #循環過程當中不斷調用yield,就會不斷中斷。固然要給循環設置一個條件來退出循環,否則就會產生一個無限數列出來
      yield b
      a, b = b, a + b
      n = n + 1
    return 'done'

    迭代斐波那契數列for循環

  for n in fib(6): 
    print(n)    #用for循環調用generator時,是沒法獲得generator的return語句返回值的,由於生成器只能獲得yield值
  #輸出: 1
  #      1
  #      2
  #      3
  #      5
  #      8

    迭代斐波那契數列,同時輸出生成器的return值class

  g = fib(6)
  while True:
    try:
      x = next(g)
      print('g:', x)
    except StopIteration as e:
      print('Generator return value:', e.value) #想要拿到return語句返回值,必須捕獲StopIteration錯誤,返回值包含在StopIteration的value中
      break
  #輸出: g: 1
  #      g: 1
  #      g: 2
  #      g: 3
  #      g: 5
  #      g: 8
  #      Generator return value: done
相關文章
相關標籤/搜索