Python的生成器(generator)
如果函數(shù)要產(chǎn)生一系列結(jié)果,那么最簡(jiǎn)單的做法是把這些結(jié)果放在一份列表(list)中,并將其返回給函數(shù)調(diào)用者。例如我們要獲得一份文本中每個(gè)單詞的長(zhǎng)度。
def get_word(text):result = []for i, letter in enumerate(text.split(' ')):result.append(len(letter))return result輸入驗(yàn)證下:
text = 'Five score years ago, a great American, in whose symbolic shadow we stand today, signed the Emancipation Proclamation.'print(get_word(text))輸出結(jié)果:
[4, 5, 5, 4, 1, 5, 9, 2, 5, 8, 6, 2, 5, 6, 6, 3, 12, 13]這個(gè)get_word()函數(shù)本身沒(méi)有問(wèn)題,但是有2個(gè)方面值得注意,一是這個(gè)函數(shù)稍顯擁擠,需要預(yù)先定義一個(gè)列表,然后在循環(huán)中添加元素,最后返回,并不是很簡(jiǎn)練,當(dāng)然這不是什么大問(wèn)題。二是當(dāng)你有大量數(shù)據(jù)并把所有值放在內(nèi)存時(shí),這種處理方式可能并不是很好,例如text文本非常大,有好幾個(gè)GB,就無(wú)法使用這種方式了。
這時(shí),需要用到生成器(generator),生成器就是使用yield表達(dá)式的函數(shù),使用很簡(jiǎn)單,直接把你函數(shù)需要返回的列表內(nèi)容前面加上yield即可。如上面那個(gè)函數(shù),改寫(xiě)如下:
def gen_get_word(text):for i, letter in enumerate(text.split(' ')):yield len(letter)可以看到,這個(gè)改寫(xiě)后的函數(shù)清晰了許多,沒(méi)有列表的定義、添加元素、返回列表等,列表中的元素,現(xiàn)在都分別傳給yield了??纯丛囼?yàn)結(jié)果:
print(list(gen_get_word(text)))輸出:
[4, 5, 5, 4, 1, 5, 9, 2, 5, 8, 6, 2, 5, 6, 6, 3, 12, 13]這和最開(kāi)始的函數(shù)得到的結(jié)果是一致的。
生成器的優(yōu)點(diǎn)是它無(wú)須將對(duì)象的所有元素都存入內(nèi)存后,才開(kāi)始進(jìn)行操作。而是僅在迭代至某個(gè)元素時(shí)才會(huì)將該元素放入內(nèi)存。這個(gè)特點(diǎn)使得它特別適合用于遍歷一些巨大序列對(duì)象,例如大文件、大集合、大字典等。這個(gè)特點(diǎn)也被稱為延遲計(jì)算或惰性求值(lazy evaluation),可以有效的節(jié)省內(nèi)存空間。
例如,如果直接對(duì)文件對(duì)象調(diào)用read()方法,會(huì)導(dǎo)致不可預(yù)測(cè)的內(nèi)存占用??梢杂蒙善髯x取固定長(zhǎng)度的緩沖區(qū),不用將文件一次性讀入內(nèi)存。
def read_file(path):with open(path, 'rb') as f:while True:block = f.read(1024)if block:yield blockelse:return總結(jié)下:
- 所有需要返回序列對(duì)象的函數(shù)都可以使用生成器。
- 使用生成器比收集結(jié)果放入列表然后返回的方式更加簡(jiǎn)練清晰。
- 生成器函數(shù)返回的是一個(gè)迭代器,可以把傳給yield些值,逐次產(chǎn)生出來(lái)。
- 生成器不會(huì)影響內(nèi)存的消耗,特別適合于處理大數(shù)據(jù)文件、大的數(shù)據(jù)對(duì)象等。
總結(jié)
以上是生活随笔為你收集整理的Python的生成器(generator)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: python列表的append和exte
- 下一篇: 为什么OpenCV3在Python中导入