Python 高級特性(4)- 生成器 generator


列表生成式

通過上一篇介紹 列表生成式文章可以知道,它可以快速創建我們需要的列表

 

局限性

  • 受內存限制,列表生成式創建的列表的容量肯定有限的
  • 不僅占用很大的存儲空間,如果我們僅僅需要訪問前幾個元素,那后面絕大多數元素占用的空間都白白浪費了

 

什么是生成器

  • 若列表元素可以按照某種算法算出來,就可以在循環的過程中不斷推算出后續需要用的元素,而不必創建完整的 list,從而節省大量的空間
  • 邊循環邊計算的機制,叫生成器(generator)

 

最簡單的生成器

L = [x * x for x in range(10)]
print(L)
print(type(L))

L = (x * x for x in range(10))
print(L)
print(type(L))

# 輸出結果
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
<class 'list'>
<generator object <genexpr> at 0x000001D607541EB8>
<class 'generator'>

只要把一個列表生成式的 [] 改成 () ,就創建了一個 generator

 

如何打印生成器每個元素

直接簡單 for 循環

L2 = (x * x for x in range(10))

for i in L2:
    print(i)

 

next() 方法

可以獲取 generator 的下一個元素

基本不會使用這個

L2 = (x for x in range(10))
print(next(L2))
print(next(L2))
print(next(L2))
print(next(L2))
print(next(L2))
print(next(L2))

# 輸出結果
0
1
2
3
4
5

 

還有另一個方法 .__next()__

L2 = (x for x in range(10))
print(L2.__next__())
print(L2.__next__())
print(L2.__next__())
print(L2.__next__())
print(L2.__next__())
print(L2.__next__())

# 輸出結果
0
1
2
3
4
5

 

生成器的迭代原理

generator 能夠迭代的關鍵就是 next() 方法,通過重復調用 next() 方法,直到捕獲一個異常

 

yield 函數

  • 帶有 yield 的函數不再是一個普通函數,而是一個生成器 generator
  • yield 相當於 return 返回一個值,並且記住這個返回值的位置,下次迭代時,代碼會從 yield 的下一條語句開始執行,直到函數結束或遇到下一個 yield 

 

普通的斐波拉契數列

1, 1, 2, 3, 5, 8, 13, 21, 34, ...,除第一個和第二個數外,任意一個數都可由前兩個數相加得到

# 斐波拉契數列
def fib(max):
    n, a, b = 0, 0, 1
    while n < max:
        print(b)
        a, b = b, a + b
        n = n + 1

fib(8)

# 輸出結果
1
1
2
3
5
8
13
21

它和生成器很像,知道第一個元素值,就可以推算后面的任意個元素了

 

是用 yield 的斐波拉契數列

def fib(max):
    n, a, b = 0, 0, 1
    while n < max:
        yield b
        a, b = b, a + b
        n = n + 1

fib(8)
print(fib(8))

# 輸出結果
1
1
2
3
5
8
13
21
<generator object fib at 0x00000246A5001EB8>

 

生成器的執行流程

函數是順序執行,遇到 return 或者最后一行執行完就返回

 

而生成器的執行流程是

  • 每次調用 next() 或 for 循環的時候執行,遇到 yield 就返回
  • 一個生成器里面可以有多個 yield
  • 再次執行時從上次返回的 yield 語句處繼續執行
# 執行流程
def odd():
    print('step 1')
    yield 1
    print('step 2')
    yield 3
    print('step 3')
    yield 5

L = odd()
for i in L:
    print(i)

# 輸出結果
step 1
1
step 2
3
step 3
5

 

生成器的工作原理

  • 它是在 for 循環過程中不斷計算下一個元素,並在適當的條件結束 for 循環
  • 對於函數改成的 generator 來說,,遇到 return 語句或者執行到函數最后一行時,就是結束 generator 的指令,for 循環隨之結束

 

生成器的優點

在不犧牲過多速度情況下,釋放了內存,支持大數據量的操作

 

不使用生成器下的代碼

from tqdm import tqdm

a = []
for i in tqdm(range(10000000)):
    temp = ['你好'] * 2000
    a.append(temp)

for ele in a:
    continue

 

運行結果

可以看到開始運行大數據量循環代碼后,內存暴增,並且占滿了電腦所有內存,很明顯這是不合理且不可接受的!

 

使用生成器的代碼

def test():
    for i in tqdm(range(10000000)):
        temp = ['你好'] * 2000
        yield temp

a = test()
for ele in a:
    continue

 

運行結果

 內存絲滑的很,奈斯!

 

生成器的應用場景

當然就是需要處理大數據量的場景了,比如一個文件有幾百萬行數據,或者有幾百萬個文件需要分別讀取處理

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM