小結-Python-可迭代、迭代器和生成器的區別

可迭代對象

可迭代對象指的是定義了_ _ 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=" ")

關系圖

屏幕快照 2019-05-05 21.36.33.png
  1. 迭代器一定是一個可迭代對象,因為既有可迭代對象的iter方法,也有可迭代對象不具備的next方法。
  2. 但反過來,可迭代對象卻不一定是一個迭代器,但能通過iter函數實現。
  3. 迭代器可以通過next函數訪問下一個值,也可以和可迭代對象一樣for循環遍歷。
  4. 生成器就是用來創建迭代器的函數,使用yield關鍵字,返回一個生成器。
  5. 生成器既是一個可迭代對象,也是一個迭代器。
  6. for循環就是迭代器調用next函數依次訪問下一個值。
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 這本書是朋友前天推薦的,在當當上搜了一下,看了一眼作者——古典,就毫不猶豫地下單了。之前讀過古典老師的《拆掉思維里...
    米唐米唐_閱讀 722評論 6 20
  • 車間主任是云南人,走起路來頭向前,兩肩來回擺動的幅度很大,兩腳抬得很高,顯得趾高氣揚的。其實他就是一個混吃混喝的主...
    5278a0f4f595閱讀 293評論 1 8
  • 創建一個webView :UIWebView*_myWebView=[[UIWebViewalloc]initWi...
    bingo哥閱讀 773評論 0 0
  • 對于玉而言~有人說玉是金錢,有人說玉是玩物,有人說玉是寄托,也有人說玉是哲學,玉是生命,玉是世間萬物。 的確,每一...
    玉無憂yjj閱讀 292評論 0 0