生成器可以理解為一種數(shù)據(jù)類型,這種數(shù)據(jù)類型自動實(shí)現(xiàn)了迭代器協(xié)議(其它的數(shù)據(jù)類型需要調(diào)用自己內(nèi)置的_iter_方法),所以生成器就是可迭代對象。Python有兩種不同的方式提供生成器。
1. 生成器函數(shù):使用yield 而不是return語句返回結(jié)果。yield語句一次返回一個(gè)結(jié)果。在每個(gè)結(jié)果中間,掛起函數(shù)的狀態(tài),以便下次從它離開的地方繼續(xù)執(zhí)行。yield函數(shù)的功能:
a. 把函數(shù)的結(jié)果做生迭代器(以一種優(yōu)雅的方式封裝好_iter_, _next_)
b. 函數(shù)的暫停與再繼續(xù)運(yùn)行有yield控制
yield與return的比較:
相同點(diǎn):都有返回值的功能
不同點(diǎn):return只能返回一次值,yield可以返回多次值
2. 生成器表達(dá)式:類似于列表推導(dǎo)。但是,生成器返回按需產(chǎn)生結(jié)果的一個(gè)對象,而不是一次構(gòu)建一個(gè)結(jié)果列表。如
g=('egg%s' %i for i in range(1000))
print(g)
print(next(g))
print(next(g))
print(next(g))
生成器應(yīng)用:讀取大文件:如:
有一個(gè)文件有1T左右,并且只有一行,行之間有分隔符,我們需要把文件內(nèi)的數(shù)據(jù)一行一行讀取出來,然后寫入數(shù)據(jù)庫里面。
分析:遇到超大文件,不能直接放在內(nèi)存中。要分段進(jìn)行讀取,以減少內(nèi)存的占用
由于它只有一行,如果這樣讀取的話,1T 內(nèi)存誰也承受不了
with open("file","r") as f:
for i in f.readlines()
? ? ? ? print(i)
除了f.readlines(),可以用另外一個(gè)函數(shù) file.read()
1.f.read() 函數(shù)并不是一次讀取所有,可以傳入 int 參數(shù),代表讀取的字符數(shù)
2.連續(xù)調(diào)用,可以讀取偏移量的值 。
import os
filepath = os.path.dirname(os.path.abspath('.'))+"http://a.txt"
def Myread(f,newlineseperator):
buffer ='' #暫存讀取的數(shù)據(jù)
? ? while True:
while newlineseperatorin buffer:#判斷 分隔符是否存在暫存數(shù)據(jù)
? ? ? ? ? ? pos = buffer.index(newlineseperator)#用了index方法并且返回分隔符的下表
? ? ? ? ? ? yield buffer[:pos]#取分隔符前面的值保存在生成器
? ? ? ? ? ? buffer=buffer[pos+len(newlineseperator):]#取過值也更新buffer,刪除前面取得值加上分隔符
? ? ? ? chunk = f.read(50)# 一次50個(gè)字符
? ? ? ? if not chunk:#如果取不到值了,就用這個(gè)結(jié)束循環(huán)
? ? ? ? ? ? yield buffer#最后一個(gè)分隔符后邊的值加上再次取到的chunk值
? ? ? ? ? ? break
? ? ? ? buffer = buffer + chunk
with open(filepath,"r")as f:
for iin Myread(f,newlineseperator="{|}"):
print(i)