python-生成器(通俗詳解)

生成器:含有yield的函數。(無需藉助類就能實現)

功能:函數執行過程中可中斷、可重開、可暫停、可續傳

爲什麼要用生成器? 解決內存佔用問題,看最後一段代碼。

原理:是基於迭代器來實現(既然生成器是一個迭代器,它可以被用在for 循環中),內部會自動創建__iter__()和__next__()方法。

運行規則:

遇到yield,程序暫停,並返回值,下次還從該位置運行

對比return則是程序停止,並返回值

基本語法:

def myGen():
    print('生成器執行')
    yield 1
    yield 2

使用方法1:

>>> my = myGen()
>>> next(my)
    生成器執行
    1

>>> next(my)
    2

>>> next(my)
    錯誤:StopIteration

使用方法2:

    通過迭代器可知,for循環可以捕獲StopIteration,並結束
>>> for i in myGen():
        print(i)
    生成器執行
    1
    2

生成器推導式:

e = (i for i in range(5))  # e 也是一個生成器
next(e)
0
next(e)
1
for each in e:
    print(each)
2
3
4

生成器的另一種結構:

def foo():
    while True:
        res = yield 4
        print("res:",res)
        
g = foo()	# 得到了生成器
print(next(g))	# 開始運行生成器g,第一次返回值爲4,此時生成器停止
print(next(g))	# 第二次運行:由於4被返回。所以並沒有賦值給res,res爲None,返回4

# 運行結果
4
res: None
4

代碼解析:

g = foo()

g得到了生成器

 print(next(g))

開始運行生成器g,第一次返回值爲4,此時生成器停止

 print(next(g))

第二次運行:由於4被返回。所以並沒有賦值給res,res爲None,返回4

注意:和一般的賦值語句不同,res的值並不是通過yield後面的值賦值的吼

(因爲後面的值被返回了,怎麼賦?怎麼賦?沒法賦!沒法賦!)

那麼res的值時誰賦予的呢?
我們再來看一個小栗子:

def foo():
    while True:
        res = yield 4
        print("res:",res)
        
g = foo()	# 得到了生成器
print(next(g))	# 開始運行生成器g,第一次返回值爲4,此時生成器停止

# 以上:和之前一樣
print(g.send(7))	# 生成器g 的send()方法,從外部把7送到了生成器內部,賦值給了res

# 運行結果
4
res: 7
4

代碼解析:

print(g.send(7))	:

生成器g的send()方法: 從外部把7送到了生成器內部,賦值給了res

由此可見:res的值是通過send()方法,從外部傳遞的

調用send()與使用next()有點像,都會使生成器進行下一次運行。不同的是send()可以往裏傳入一個值給res

小栗子:

10 以內的素數之和是:2 + 3 + 5 + 7 = 17
那麼請編寫程序,計算 2000000 以內的素數之和

如果先把所有的素數找到存在列表裏,再累加求和,則佔用太大內存可能溢出
用生成器:一次找到一個素數,找一個加一個,不佔用內存

import math

# 判斷是否爲素數
def is_prime(number):       
    if number > 1:
        if number == 2:
            return True
        if number % 2 == 0:
            return False
        for current in range(3, int(math.sqrt(number) + 1), 2):
            if number % current == 0:
                return False
        return True
    return False

# 生成器函數
def get_primes(number):
    while number:
        if is_prime(number):
            yield number
        number -= 1


a = 0   
for each in get_primes(2000000):
    a += each   # 每次產生一個值累加

print(a)    # 142913828922

如果你感覺對你有幫助,你的讚賞是對我最大的支持!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章