-->>>我的原文鏈接
一脸候、生成器
首先提一個(gè)問題:
range(5) 和list(range(5)) 有何區(qū)別决摧?
大家可以嘗試在Python shell里鍵入這兩個(gè)命令看看是何結(jié)果岂贩。沒有意外的話洲押,前者返回range(0,5)
谅辣,后者返回[0, 1, 2, 3, 4]
袄琳。說明前者是一個(gè)range對(duì)象漾橙,后者是一個(gè)列表杆融。
這還不是關(guān)鍵,我們分別定義一個(gè)range和相應(yīng)的列表霜运,看看前后內(nèi)存占用的變化脾歇。
>>> print(psutil.Process(os.getpid()).memory_info().rss)
18161664
>>> x = list(range(10000000))
>>> print(psutil.Process(os.getpid()).memory_info().rss)
423337984 # 內(nèi)存占用明顯提升
>>> y = range(100000000000)
>>> print(psutil.Process(os.getpid()).memory_info().rss)
423337984 # 內(nèi)存占用幾乎不變
這其實(shí)就是生成器和普通列表的區(qū)別了。生成器在內(nèi)存當(dāng)中存儲(chǔ)的是序列生成的邏輯淘捡,而我們一般用的列表藕各,則是實(shí)實(shí)在在地把列表數(shù)據(jù)項(xiàng)放在內(nèi)存里了。
應(yīng)該可以體會(huì)到焦除,當(dāng)我們進(jìn)行大數(shù)據(jù)的處理時(shí)激况,這是有顯著差異的。
除此之外膘魄,我們?cè)賮砜纯刺幚頃r(shí)間乌逐,應(yīng)該不難猜到,原理同上瓣距。
import time
t1 = time.time()
x = range(1000000)
t2 = time.time()
y = list(range(1000000))
t3 = time.time()
print(f'Time consumed for using range: {t2-t1}')
print(f'Time consumed for using list: {t3-t2}')
# Output
Time consumed for using range: 2.62e-06
Time consumed for using list: 0.031
確實(shí)黔帕,使用range幾乎不占用任何時(shí)間,而用list則需要占用大量的時(shí)間蹈丸。當(dāng)然聰明的人一眼能看出成黄,range只是定義了生成邏輯,真正提取數(shù)據(jù)項(xiàng)的時(shí)候還是需要時(shí)間的嘛逻杖,沒錯(cuò)奋岁,但是這兩個(gè)邏輯是不一樣的。使用range的時(shí)候荸百,我們每生成一項(xiàng)就可以對(duì)這個(gè)數(shù)據(jù)進(jìn)行一些操作闻伶,但如果使用list,必須得等整個(gè)列表生成完畢才能操作够话。這就是為什么我們寫for循環(huán)的時(shí)候都是寫for i in range(x)
的原因了蓝翰。
二光绕、yield關(guān)鍵字
yield關(guān)鍵字用于函數(shù)中,將該函數(shù)的返回結(jié)果變成生成器畜份〉剩看下面例子,給定一個(gè)數(shù)組x爆雹,需要返回一個(gè)新數(shù)組停蕉,其中每一項(xiàng)為原數(shù)組的平方:
# 返回list
def SquareList(x):
result = []
for i in x:
result.append(i * i)
return result
# 返回生成器
def SqaureGen(x):
for i in x:
yield i * i
gen = SqaureGen([1,2,3,4])
for i in gen:
print(i)
# Output:
1
4
9
16
其中SquareGen函數(shù)通過yield關(guān)鍵字返回了一個(gè)生成器,效果同第一節(jié)解釋的情況钙态。