迭代器和可迭代對象
由for循環的內部原理說起
list01
=
[
2
,
434
,
5
,
6
,
8
]
for
item
in
list01
:
print
(
item
)
大家有沒有想過list類型對象為什么可以被for循環呢?
能夠被for循環的條件是:它是可迭代對象(iterable)。
那么什么是
可迭代對象
呢?
參考一下內置函數item()的官方說明文檔:
iter(object[, sentinel])
返回一個 iterator對象。根據是否存在第二個實參,第一個實參的解釋是非常不同的。如果沒有第二個實參,object 必須是支持迭代協議(有 iter () 方法)的集合對象,或必須支持序列協議(有 getitem () 方法,且數字參數從 0 開始)。如果它不支持這些協議,會觸發 TypeError。如果有第二個實參 sentinel,那么 object 必須是可調用的對象。這種情況下生成的迭代器,每次迭代調用它的 next () 方法時都會不帶實參地調用 object;如果返回的結果是 sentinel 則觸發 StopIteration,否則返回調用結果。
由此我們可以明確知道什么是可迭代的對象:即對象實現了能返回迭代器的 iter 方法,或對象實現了 getitem 方法,而且其參數是從零開始的索引。(兩者都實現也行)
一文讀懂Python可迭代對象、迭代器和生成器
判斷一個對象是否是可迭代對象:
# 看對象是否具有__iter__方法 或 __getitem__方法.(dir()內置方法將生成一個列表囊括對象所有方法),若具有就說明
# 它是一個可迭代對象
>>
>
'__iter__'
in
dir
(
[
]
)
True
>>
>
'__getitem__'
in
dir
(
[
]
)
#還要進一步看其數字參數是否從 0 開始
True
>>
>
情況一:實現了能返回迭代器的__iter__方法(迭代器是具有
__next__()
方法的對象)。
class
SkillIterator
:
"""
迭代器
"""
def
__init__
(
self
,
target
)
:
self
.
target
=
target
self
.
index
=
0
def
__next__
(
self
)
:
# 如果索引越界 則拋出StopIteration異常
if
self
.
index
>
len
(
self
.
target
)
-
1
:
raise
StopIteration
# 返回下一個元素
item
=
self
.
target
[
self
.
index
]
self
.
index
+=
1
return
item
class
SkillManager
:
"""
可迭代對象
"""
def
__init__
(
self
,
skills
)
:
self
.
skills
=
skills
def
__iter__
(
self
)
:
# 創建迭代器對象 傳遞 需要迭代的數據
return
SkillIterator
(
self
.
skills
)
情況二:對象實現了 getitem 方法,而且其參數是從零開始的索引,python解釋器會創建一個迭代器并嘗試按順序(從索引 0 開始)獲取元素。
class
Eter_a
:
def
__init__
(
self
,
text
)
:
self
.
sub_text
=
text
.
split
(
" "
)
def
__getitem__
(
self
,
index
)
:
return
self
.
sub_text
[
index
]
ob_a
=
Eter_a
(
"Hello world!"
)
for
i
in
ob_a
:
print
(
i
)
一般我們不用getitem去實現一個迭代器,所以重點還是放在 __iter__上好了。
補充一下:標準迭代器里面大部分都同時實現了__next__和__iter__方法。所以有人這樣說:
內部含有'__iter__'并且含有"__next__"方法的對象,就是迭代器
for循環內部原理
實際執行情況如下圖:
1)調用可迭代對象的__inter__方法返回一個迭代器對象(iterator)
2)不斷調用迭代器的__next__方法返回元素
3)知道迭代完成后,處理StopIteration異常
根據以上條件,我們使用while來模擬一下for循環:
# 1. 獲取迭代器對象
list01
=
[
2
,
434
,
5
,
6
,
8
]
iterator
=
list01
.
__iter__
(
)
#(1)先調用__iter__方法獲取一個迭代器
while
True
:
try
:
item
=
iterator
.
__next__
(
)
# (2)不斷調用迭代器的__next__方法
print
(
item
)
except
StopIteration
:
#(3)直到捕獲StopIteration異常停止迭代
break
# (4)跳出循環體
,
生成器generator
(首先它是一個函數,特殊之處在于函數使用yield返回,這樣在調用此函數時會返回一個生成器對象,這是一個函數到對象的神奇過程,體現了一種惰性返回的思維(即用到才返回,不用不返回,而不是管你用不用哪怕只用一部分也一次性全部返回return)。生成器是迭代器的一種,明白了吧,想更深入理解就往下看)
生成器及其作用
python 生成器和迭代器有這篇就夠了
通過列表生成式,我們可以直接創建一個列表,但是,受到內存限制,列表容量肯定是有限的,而且創建一個包含100萬個元素的列表,不僅占用很大的存儲空間,如果我們僅僅需要訪問前面幾個元素,那后面絕大多數元素占用的空間都白白浪費了。
所以,如果列表元素可以按照某種算法推算出來,那我們是否可以在循環的過程中不斷推算出后續的元素呢?這樣就不必創建完整的list,從而節省大量的空間,在Python中,這種一邊循環一邊計算的機制,稱為生成器:generator
生成器是一個特殊的程序,可以被用作控制循環的迭代行為,python中生成器是迭代器的一種,使用yield返回值函數,每次調用yield會暫停,而可以使用next()函數和send()函數恢復生成器。
生成器類似于返回值為數組的一個函數,這個函數可以接受參數,可以被調用,但是,不同于一般的函數會一次性返回包括了所有數值的數組,生成器一次只能產生一個值,這樣消耗的內存數量將大大減小,而且允許調用函數可以很快的處理前幾個返回值,因此生成器看起來像是一個函數,但是表現得卻像是迭代器。
生成器:generator
1.定義:能夠動態(循環一次計算一次返回一次)提供數據的可迭代對象。
2.作用:在循環過程中,按照某種算法推算數據,不必創建容器存儲完整的結果,從而節省內存空間。數據量越大,優勢越明顯。
3.以上作用也稱之為延遲操作或惰性操作,通俗的講就是在需要的時候才計算結果,而不是一次構建出所有結果。
生成器函數
1.定義:
含有yield語句的函數,返回值為生成器對象
。
2. 創建語法
def
函數名
(
)
:
…
yield
數據
…
– 調用:
for
變量名
in
函數名
(
)
:
語句
3.說明:
- 調用生成器函數將返回一個生成器對象,不執行函數體。
- yield翻譯為”產生”或”生成”
4.執行過程:
(1) 調用生成器函數會自動創建迭代器對象。
(2) 調用迭代器對象的__next__()方法時才執行生成器函數。
(3) 每次執行到yield語句時返回數據,暫時離開。
(4) 待下次調用__next__()方法時繼續從離開處繼續執行。
5.原理:生成迭代器對象的大致規則如下
- 將yield關鍵字以前的代碼放在next方法中。
-
將yield關鍵字后面的數據作為next方法的返回值。
(qz理解:或者說當內部調用next方法時,會跳到yield關鍵字之前的代碼繼續執行,并且將yield關鍵字后面的數據作為next方法的返回值,因為調試的話執行next會跳到yield關鍵字之前的代碼。)
內置生成器
1,枚舉函數enumerate
1).語法:
for
變量
in
enumerate
(
可迭代對象
)
:
語句
for
索引
,
元素
in
enumerate
(
可迭代對象
)
:
語句
2).作用:遍歷可迭代對象時,可以將索引與元素組合為一個元組。
2,zip函數
1).語法:
for
item
in
zip
(
可迭代對象
1
,
可迭代對象
2
…
.
)
:
語句
2).作用:將多個可迭代對象中對應的元素組合成一個個元組,生成的元組個數由最小的可迭代對象決定。
生成器表達式
1.定義:用推導式形式創建生成器對象。
2.語法:變量 = ( 表達式 for 變量 in 可迭代對象 [if 真值表達式] )
(注意:可不要誤解是元組推導式,不存在元組推導式,因為元組是不可變序列)
>>
>
(
i
for
i
in
range
(
1
,
10
)
)
<
generator
object
<
genexpr
>
at
0x0000023A9DDA7408
>
>>
>
[
i
for
i
in
range
(
1
,
10
)
]
[
1
,
2
,
3
,
4
,
5
,
6
,
7
,
8
,
9
]
>>
>
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
