Python3 迭代器深入解析

測試工匠麻辣燙發表於2020-07-16

第6章 函式

  • 6.1 函式的定義和呼叫
  • 6.2 引數傳遞
  • 6.3 函式返回值
  • 6.4 變數作用域
  • 6.5 匿名函式(lambda)
  • 6.6 遞迴函式
  • 6.7 迭代器
  • 6.8 生成器
  • 6.9 裝飾器

6.7 迭代器

可迭代物件iterable

首先可以使用isinstance(物件名,Iterable)驗證某一物件是否為可迭代物件

# 驗證字串、元組、列表、字典、集合型別是否為可迭代物件
from collections.abc import Iterable
int1 = 12306
str1 = "MondayTuesdaywednesdayThursdayFridaySaturdaySunday"
tuple1 = ("Monday", "Tuesday", "wednesday", "Thursday", "Friday", "Saturday", "Sunday")
list1 = ["Monday", "Tuesday", "wednesday", "Thursday", "Friday", "Saturday", "Sunday"]
dict1 = {"Monday": "星期一", "Tuesday": "星期二", "wednesday": "星期三", "Thursday": "星期四", "Friday": "星期五", "Saturday": "星期六",
         "Sunday": "星期日", }
set1 = {"Monday", "Tuesday", "wednesday", "Thursday", "Friday", "Saturday", "Sunday"}
print(isinstance(int1, Iterable))
print(isinstance(str1, Iterable))
print(isinstance(tuple1, Iterable))
print(isinstance(list1, Iterable))
print(isinstance(dict1, Iterable))
print(isinstance(set1, Iterable))
output:
False
True
True
True
True
True
# 驗證的結果是字串、元組、列表、字典、集合型別都是可迭代物件,數值不是可迭代物件。

可迭代物件的意思就是說這個實體是可迭代的,例如字串、列表、元組、字典、集合、迭代器等等,可以用for ... in進行迴圈,

# 那麼都可用for迴圈進行迭代取值,以元組為例
tuple1 = ("Monday", "Tuesday", "wednesday", "Thursday", "Friday", "Saturday", "Sunday")
for i in tuple1:
    print(i,end=',')
output:
Monday,Tuesday,wednesday,Thursday,Friday,Saturday,Sunday,

可以使用for迴圈迭代的標誌是每個物件內部實現了__iter__方法,驗證下每個可迭代物件是否有這個方法

str1 = "MondayTuesdaywednesdayThursdayFridaySaturdaySunday"
tuple1 = ("Monday", "Tuesday", "wednesday", "Thursday", "Friday", "Saturday", "Sunday")
list1 = ["Monday", "Tuesday", "wednesday", "Thursday", "Friday", "Saturday", "Sunday"]
dict1 = {"Monday": "星期一", "Tuesday": "星期二", "wednesday": "星期三", "Thursday": "星期四", "Friday": "星期五", "Saturday": "星期六", "Sunday": "星期日", }
set1 = {"Monday", "Tuesday", "wednesday", "Thursday", "Friday", "Saturday", "Sunday"}
print(("__iter__" in dir(str1)))
print(("__iter__" in dir(tuple1)))
print(("__iter__" in dir(list1)))
print(("__iter__" in dir(dict1)))
print(("__iter__" in dir(set1)))
output:
True
True
True
True
True

可迭代物件不是迭代器,如何變成迭代器呢?

# 可迭代物件通過呼叫__iter__方法就變成迭代器物件
tuple1 = ("Monday", "Tuesday", "wednesday", "Thursday", "Friday", "Saturday", "Sunday")
t1 = tuple1.__iter__()
print(t1)
output:
<tuple_iterator object at 0x0000027B44442EC8> # iterator的意思是迭代器

先稍微總結下,可迭代物件都有__iter__方法,而沒有__next__方法。迭代器是怎麼來的?是通過可迭代物件呼叫__iter__方法來生成一個迭代器物件,那麼迭代器物件就擁有了__iter____next__方法。

# 驗證下迭代器是否有__next__方法
tuple1 = ("Monday", "Tuesday", "wednesday", "Thursday", "Friday", "Saturday", "Sunday")
t1 = tuple1.__iter__()
print(t1)
print("__next__" in dir(t1))
output:
<tuple_iterator object at 0x000001D7F73E2EC8>
True

可迭代物件可通過索引取值、遍歷取值,那麼迭代器如何取值呢?

# 迭代器使用next()取值
# tuple1 = ("Monday", "Tuesday", "wednesday", "Thursday", "Friday", "Saturday", "Sunday")
t1 = tuple1.__iter__()
print(t1)
print(t1.__next__())
print(t1.__next__())
print(t1.__next__())
print(t1.__next__())
print(t1.__next__())
print(t1.__next__())
print(t1.__next__())
output:
<tuple_iterator object at 0x000001D7F73E2EC8>
Monday
Tuesday
wednesday
Thursday
Friday
Saturday
Sunday
StopIteration 
# 最後一次取值時報錯了,next一次取一個值,取完後來通過報StopIteration這個錯誤結束。

講了這麼多到底什麼是迭代器?

在Python中,迭代器是遵循迭代協議的物件,通過呼叫可迭代的物件的__iter__方法生成迭代器物件,迭代器物件具有__next__方法,可通過此方法對迭代器取值。

這時能理解for語句如何實現遍歷的嗎?for語句通過呼叫可迭代物件的__iter__方法,這個方法返回一個迭代器,for語句迴圈呼叫迭代器內的每個元素的__next__方法,當迭代器為空時,__next__方法會引發一個StopIteration異常,這個異常會告訴for語句終止迴圈。

迭代器到底有什麼用呢?

節約記憶體空間:文字檔案本身是迭代器物件,用迭代器的方式訪問檔案時,可以每次讀取一行,而不必一次性將整個檔案讀入,節約記憶體。

# r1.txt文字檔案內容
"""
Monday
Tuesday
wednesday
Thursday
Friday
Saturday
Sunday
"""

r1 = open("r1.txt")
print(r1.__next__(), end="")
print(r1.__next__(), end="")
output:
Monday
Tuesday

迭代

講完迭代器後,迭代就比較好理解了,迭代就是從迭代器中取元素的過程

比如我們用for迴圈從train = "12306"中取元素,這種遍歷過程就被稱作迭代

# for迴圈的物件必須是可迭代物件,如果這個物件不是,那麼會報錯
train = 12306
for i in train:
    print(i)
output:
TypeError: 'int' object is not iterable

如果你不想用for迴圈迭代呢?這時你可以:

  1. 先呼叫容器(以字串為例)的iter()函式
  2. 再使用 next() 內建函式來呼叫 next() 方法
  3. 當元素用盡時,next() 將引發 StopIteration 異常

# 定義一個字串
>>> train = "12306"
>>> it = iter(train)
>>> it
<str_iterator object at 0x000001E30D71BE48>
>>> next(it)
'1'
>>> next(it)
'2'
>>> next(it)
'3'
>>> next(it)
'0'
>>> next(it)
'6'
>>> next(it)
Traceback (most recent call last):
  File "<input>", line 1, in <module>
StopIteration

# 用while迴圈模擬實現上面的過程
def while_iterator(iterable_obj):
    iterator_obj = iter(iterable_obj)
    while 1:
        try:
            print(next(iterator_obj), end=' ')
        except StopIteration:
            return
train = "12306"
while_iterator(train)
output:
1 2 3 0 6 

相關文章