什么是生成器?
它內部封裝了一套公式/演算法,只有等到需要呼叫/執行資料的時候 --》執行next()函式
才會將公式計算得到的資料結果回傳給程式,這就是生成器的原理(核心思想)
格式:兩種
執行完畢都回傳generator型別物件
格式一:
(運算式 for 形參串列 in 容器物件 if ...)
格式二:
定義函式,在函式的內部需要使用yield關鍵字來記錄回傳的generator物件的資料公式,
【注意】:此時函式就算有return,已經無視了,回傳的一定是一個generator型別的物件(即生成器物件)
【注意事項】:
1).生成器中是沒有真實資料存在的,所以我們是不能直接使用len()函式來嘗試得到其長度;
如果我們這么做了,錯誤提示:no len()
2).生成器關聯的真實資料只能被使用一次,不可逆;如果超量呼叫,會報錯:StopIteration
比較:串列生成式和生成器?
對于生成器而言:
定義執行后會得到一個generator物件,
此物件中沒有真實資料(第一手值),它內部封裝了一套公式/運算式
一旦需要使用資料了,就會去計算公式,得到內容;
就因為其這樣的特點,所以我們得出一些結論:
1).生成器比較節省記憶體資源(好處)
2).生成器(剛生成的時候沒有值)所以在資料運算效率上比串列生成式要低下一點(弊端)
對于串列生成式而言:
定義執行后會得到一個list物件,
串列中的資料已經確定(真實資料已經進記憶體),
就因為其這樣的特點,所以我們得出一些結論:
1).串列生成式比較占用記憶體資源(弊端)
2).串列生成式在運算時比生成器要效率更好(好處)
演示生成器的定義以及使用,關注其一些注意事項;
方式一:
格式:
(運算式 for 引數串列 in 容器物件 if...)
gen = (x for x in range(5))
print(gen,type(gen))
#generator物件不能配合len()來獲取其長度,因為它根本沒有長度
# print(len(gen))
#使用next()函式來得到每一次generator中的內容
print(next(gen)) #得到0
print(next(gen)) #得到1
print(next(gen)) #得到2
print(next(gen)) #得到3
print(next(gen)) #得到4
#generator物件中的資料內容只能被決議使用一次,不可逆;一旦呼叫多了,直接報錯了 --> StopIteration
# print(next(gen))
兩種處理接續generator物件的方式,
方式一:使用next()函式呼叫傳入generator物件即可,此方式如果呼叫next()次數過多;報錯了:StopIterator
方式二:使用回圈處理,這種方式不會過量的呼叫內部運算式執行,不會報錯,比較友好
gen = (x for x in range(5))
print(gen,type(gen))
print(next(gen)) #得到0
print(next(gen)) #得到1
print(next(gen)) #得到2
for g in gen:
print(g) #得到3
4
#注意下面一行代碼有誤,因為next()只能出現迭代器物件,對于單值int、float...不能傳入的,報錯:TypeError
# print(next(g))
需求:思考如果對于以上gen物件中的資料我在開發程序中需要多次呼叫,那該怎么辦?
可以將generator型別的物件轉換為list等型別的物件即可...
gen = (x for x in [1,2,3,4,5])
# print(gen,type(gen)) 此時gen只是一個函式物件,并沒有被呼叫,所以沒有內容
lt = list(gen)
print(lt,type(lt)) #得到[1, 2, 3, 4, 5] <class 'list'>
for i in lt:
print(i) #得到 1
2
3
4
5
print('-' * 40) #得到 -----------------------------------
#這時候 list型別有資料有長度了,可以用while回圈
i = 0
while i < len(lt):
print(lt[i])
i += 1
#同樣得到 1
2
3
4
5
方式二:
定義函式,在函式內部需要使用關鍵字yield來記錄回傳的generator物件的資料公式;
執行還是通過next()函式來實作
【注意】:此時函式就算有return,已經無視了,回傳的一定是一個generator型別的物件
def func(n):
lt = []
for i in range(1,n + 1):
if i % 2 == 0:
lt.append(i)
yield i
return lt
#呼叫function(n)
f = func(10)
print(f,type(f)) ###雖然有回傳值但回傳的一定是一個generator型別的對像<generator object func at 0x0000000001E06938> <class 'generator'>
print(next(f)) #得到2
print(next(f)) #得到4
for i in f:
print(i) #得到6 該回圈接上面的走
#得到8
#得到10
但是上面的題目可以用方式一更簡單:
gen = (x for x in range(1,11) if x % 2 == 0)
for g in gen:
print(g)
#需求:實作全排列
str1 = 'ABC'
str2 = 'XYZ'
def func2(str1,str2):
for s1 in str1:
for s2 in str2:
yield s1 + s2 #yield后面加的是方式方法
gen = func2(str1,str2)
# print(gen,type(gen))
for g in gen:
print(g) #得到 AX
AY
AZ
BX
BY
BZ
CX
CY
CZ
用簡單的方法
gen = (x + y for x in str1 for y in str2)
for g in gen:
print(g)
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/179267.html
標籤:Python
上一篇:【2020Python修煉記12】Python語法入門—流程控制(if分支結構+while/for回圈結構)
下一篇:20.python迭代器
