可迭代對象
可迭代對象指的是定義了_ _ iter _ _ 方法的對象,調用該方法會返回一個迭代器對象。
可迭代對象,例如:list列表、tuple元組、帶有上述iter方法的對象等等。
# -*- coding: utf-8 -*-
from collections.abc import Iterable
from collections.abc import Iterator
# list的創建可以用list()函數和元組構建;也可以用[]和元素構成
a = list((1, 3, 5))
b = [2, 4, 6]
print(type(a), type(b))
# Output: <class 'list'> <class 'list'>
# 可見,list列表是一個可迭代對象,但不是一個迭代器;
# 也可以進入list函數中查看沒有__next__方法,只有一個__iter__方法。
x = isinstance(a, Iterable)
y = isinstance(a, Iterator)
print(x, y)
# Output: True False
# 正因為,list是一個可迭代對象,所以可以用for循環遍歷
for i in a:
# Output: 1 3 5
print(i, end=' ')
print(" ")
# 回憶以往常用的range函數就是一個可迭代對象,
# 因為進入函數內部同樣沒有__next__方法,只有一個__iter__方法。
for j in range(1, 10, 2):
# Output: 1 3 5 7 9
print(j, end=" ")
個人理解:在可迭代對象中使用for循環,實際上就是調用iter()--
迭代器
定義
迭代器就是定義_ _ next _ _ 方法的對象。每次調用上述方法就返回迭代器一個值,沒有就拋出StopIteration異常。
創建
迭代器可以由可迭代對象通過內置函數iter()函數實現,該函數會接受一個可迭代對象,返回一個迭代器對象。實際上,iter()函數內部調用可迭代對象的——iter——方法。而前面在可迭代對象中就提到,該方法會返回一個迭代器對象。
小結:可迭代對象轉化成為迭代器僅需要一個iter函數,其實質還是調用可迭代對象內部的——iter——方法去返回一個可迭代對象。
應用
迭代器如何應用?其實調用Python內置函數next函數就可以,該函數會接受一個迭代器對象,返回迭代器對象的下一個值。實際上,next()函數在內部調用了迭代器對象的——next——方法。
小結:迭代器其實多定義了一個——next——方法的可迭代對象,然后通過iter函數調用自己——iter——方法返回迭代器,讓迭代器不僅可以可以for循環遍歷,也可以通過next函數來訪問下一個值。
注意分清:__iter__方法,__next__方法;內置函數iter(),內置函數next()
所以當有一個迭代器對象的時候,就不僅可以for循環遍歷,也可以通過next函數訪問下一個輸出。
# 接前面代碼,繼續!
# 通過iter函數將可迭代對象轉化成為迭代器。
a_iter = iter(a)
print(isinstance(a_iter, Iterable), isinstance(a_iter, Iterator))
# Output: True True
# 然后使用next函數訪問下一個值
print(next(a_iter))
# Output: 1
# 這個比較有趣,發現可迭代對象一旦調用next函數,則值訪問就減少一次。
for i in a_iter:
# Output: 3 5
print(i, end=" ")
# print(next(a_iter)) Output:拋出異常,StopIteration 因為沒有下一個值。
注意
這里解釋一下,為何可迭代對象和迭代器都可以通過for循環迭代元素。
這是因為for循環對象要求一定要是可迭代對象!
所以可迭代對象可以進行for循環,而可迭代對象通過iter函數生成的迭代器也可以for循環。
因為在for循環內部,首先會調用iter函數,將需要遍歷的對象(可迭代對象)轉變成迭代器,然后在迭代器上重復調用next函數,直到拋出異常。
生成器
生成器的基本功能就是用來創建迭代器,形式上類似于普通定義函數,擁有yield關鍵字。
yield關鍵字不同于return,return后會推出相關代碼,但yield則會保留退出,下次繼續。
# 接上面代碼,繼續!
# 定義一個生成器,其形式類似函數定義,且擁有關鍵字yield
def generator_test():
yield 1
yield 2
yield 3
g = generator_test()
# Output: <class 'generator'>
print(type(g))
# 可見,生成器內部擁有以下兩個方法,自然依據定義,生成器既是可迭代對象,也是迭代器。
print(hasattr(g, '__iter__'), hasattr(g, '__next__'))
# Output: True True
# 既然是迭代器,那自然可以通過next函數訪問下一個值,也可以for循環遍歷。
print(next(g))
# Output: 1
for i in g:
# Output: 2 3
print(i, end=" ")
關系圖
- 迭代器一定是一個可迭代對象,因為既有可迭代對象的iter方法,也有可迭代對象不具備的next方法。
- 但反過來,可迭代對象卻不一定是一個迭代器,但能通過iter函數實現。
- 迭代器可以通過next函數訪問下一個值,也可以和可迭代對象一樣for循環遍歷。
- 生成器就是用來創建迭代器的函數,使用yield關鍵字,返回一個生成器。
- 生成器既是一個可迭代對象,也是一個迭代器。
- for循環就是迭代器調用next函數依次訪問下一個值。