簡體   English   中英

關於Python中的迭代器和迭代的困惑

[英]Confusion about iterators and iterables in Python

我目前正在閱讀Python 3.5的官方文檔。

它聲明range()是可迭代的,而list()for是迭代器。 [第4.3條]

但是, 這里聲明zip()創建一個迭代器。

我的問題是,當我們使用這個指令:

list(zip(list1, list2))

我們使用迭代器( list() )迭代另一個迭代器?

通過重復使用術語“迭代器”,文檔在這里產生了一些混亂。

迭代器協議有三個組件:

  1. Iterables; 事情可以潛在地迭代,並得到他們的元素,一個接一個。

  2. 迭代器; 做迭代的事情。 每當您想要遍歷迭代的所有項目時,您需要其中一項來跟蹤您在過程中的位置。 這些不可重復使用; 一旦你到達終點,就是這樣。 對於大多數迭代,您可以創建多個獨立迭代器,每個跟蹤位置獨立。

  3. 迭代器的消費者; 那些想要對這些物品做些什么的事情。

for循環是后者的一個例子,所以#3。 for循環使用iter()函數為你想要循環的任何東西生成一個迭代器 (上面的#2),這樣“what”必須是一個可迭代的(上面的#1)。

range()是#1的一個例子; 它是可迭代的對象。 您可以獨立迭代多次:

>>> r = range(5)
>>> r_iter_1 = iter(r)
>>> next(r_iter_1)
0
>>> next(r_iter_1)
1
>>> r_iter_2 = iter(r)
>>> next(r_iter_2)
0
>>> next(r_iter_1)
2

這里r_iter_1r_iter_2是兩個獨立的迭代器,每次你要求下一個項目時,他們都會根據自己的內部記賬來完成。

list()可迭代(#1)和迭代使用者(#3)的示例。 如果將另一個iterable(#1)傳遞給list()調用,則會生成一個包含該iterable中所有元素的列表對象。 但列表對象本身也是可迭代的。

在Python 3中, zip()接受多個迭代(#1),它本身就是一個迭代器(#2)。 zip()為你給它的每個iterables存儲一個新的迭代器(#2)。 每次請求zip()獲取下一個元素時, zip()使用每個包含的iterables中的下一個元素構建一個新元組:

>>> lst1, lst2 = ['foo', 'bar'], [42, 81]
>>> zipit = zip(lst1, lst2)
>>> next(zipit)
('foo', 42)
>>> next(zipit)
('bar', 81)

所以最后, list(zip(list1, list2))使用list1list2作為iterables(#1), zip()在外部list()調用正在使用它時消耗那些(#3)。

文檔措辭嚴厲。 這是你所指的部分:

我們說這樣的對象是可迭代的 ,也就是說,適合作為函數和構造的目標,這些函數和構造期望在供應耗盡之前可以獲得連續項目的東西。 我們已經看到for語句就是這樣一個迭代器 函數list()是另一個; 它從iterables創建列表:

在本段中, 迭代器不是指Python迭代器對象,而是“迭代某些東西”的一般概念。 特別是, for語句不能是迭代器對象,因為它根本不是對象; 這是一種語言結構。

要回答您的具體問題:

......當我們使用這個指令時:

 list(zip(list1, list2)) 

我們使用迭代器( list() )迭代另一個迭代器?

不, list()不是迭代器。 它是list類型的構造函數。 它可以接受任何可迭代(包括迭代器)作為參數,並使用該iterable構造列表。

zip()是一個迭代器函數,即一個返回迭代器的函數。 在您的示例中,它返回的迭代器傳遞給list() ,它從中構造一個list對象。

判斷對象是否為迭代器的一種簡單方法是使用它調用next() ,看看會發生什么:

>>> list1 = [1, 2, 3]
>>> list2 = [4, 5, 6]

>>> zipped = zip(list1, list2)
>>> zipped
<zip object at 0x7f27d9899688>
>>> next(zipped)
(1, 4)

在這種情況下,將返回zipped的下一個元素。

>>> list3 = list(zipped)
>>> list3
[(2, 5), (3, 6)]

請注意,在list3只找到迭代器的最后兩個元素,因為我們已經使用next()消耗了第一個元素。

>>> next(list3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'list' object is not an iterator

這不起作用,因為列表不是迭代器。

>>> next(zipped)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

這一次,雖然zipped是一個迭代器,但用它調用next()會引發StopIteration因為它已經用盡了構造list3

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM