Python:range 對象並不是迭代器

簡評:迭代器(iterator)是惰性可迭代對象(lazy iterable),range 函數在 Python 3 中是一個惰性的可迭代對象,那麼 range 是不是迭代器呢?為什麼。

TLNR:Python 3 中的 range 對象(Python 2 中的 xrange 對象)是 lazy 的,但 range 對象卻不是迭代器。

是的,這讓人很困惑

當談論 Python 中的迭代器(iterator)和可迭代對象(iterable)時,你很可能會聽到有人重複 range 是迭代器的誤解。我認為這是非常嚴重誤解, 如果你認為 range 對象是迭代器,那麼你關於「迭代器是如何運行」的心智模型還不夠清楚。從某種意義上來說,range 和迭代器都是「惰性」的,但它們是以相當不同的方式實現「惰性」的。

什麼是迭代器(iterator)

在 Python 中,可迭代對象就是你可以迭代的任何東西,而迭代器就是實際迭代的東西。

Iter-ables are able to be iterated over. Iter-ators are the agents that perform the iteration.

可以使用 iter 函數從任何可迭代對象中獲取迭代器:

一旦有了迭代器,可以用它做的唯一的事情就是獲得它的下一個元素:

如果沒有更多的元素了, 則會拋出一個 stop iteration exception:

所有的迭代器都是可迭代對象,意思是你可以從一個迭代器中得到一個迭代器,因此你可以遍歷一個迭代器:

應該指出的是迭代器是有狀態的,在循環遍歷一次迭代器後,如果嘗試再次循環,它將為空:

在 Python 3 中,enumerate、zip、reversed和其他一些內置函數會返回迭代器:

生成器(無論來自生成器函數還是生成器表達式)是一種創建迭代器的簡單方法:

我經常說迭代器是惰性的一次性可迭代對象。 「惰性」是因為他們只循環計算項目,「單次使用是因為一旦從一個迭代器中「消費」了一個元素之後,這個元素就永遠消失了。

什麼是 range

Python 3 中的 range 對象(Python 2 中的 xrange)可以像任何其他可迭代對象一樣循環使用:

因為 range 是可迭代對象,所以可以從中得到一個迭代器:

但 range 對象本身不是迭代器,我們不能在 range 對象上調用 next:

與迭代器不同的是,我們可以遍歷一個 range 對象而不「消耗」它:

如果我們使用迭代器完成此操作,則第二次循環時不會得到任何元素:

宗上,與 zip, enumerate, or generator對象不同,range 對象不是迭代器。

那麼,究竟 range 是什麼

range 對象在某種意義上是「惰性的」,因為它不會生成創建時包含的每個數字,相反,當我們在循環中需要的時候,它才將這些數字返回給我們。

下面是一個 range 對象和一個生成器(是一種迭代器):

不像生成器,range 對象有長度:

並且可以被索引:

與迭代器不同,你可以詢問他們是否包含某元素而不改變他們的狀態:

如果你想要一個 range 對象的描述,可以稱它們為懶序列,range 是序列(如列表,元組和字元串),但並不包含任何內存中的內容,而是通過計算來回答問題。

為什麼這個區別很重要

如果我告訴你某個對象是一個迭代器,你會知道當在這個對象上調用 iter 函數時,總會得到相同的的對象(按照定義):

確信可以在這個對象上調用 next 函數,因為可以在所有的迭代器上調用 next 函數:

而且你會知道,當遍歷它時,這些元素將從迭代器中被消耗掉,有時候這個特性可以派上用場(以特殊的方式處理迭代器):

所以雖然看起來「惰性可迭代對象」和「迭代器」之間的區別很微妙,但這些術語確實意味著不同的東西。 雖然「惰性可迭代對象」是一個沒有具體含義的非常普遍的術語,但「迭代器」這個詞意味著一個具有非常特定行為的對象。

總結

如果你知道你可以循環遍歷某個對象,這是一個可迭代對象(iterable)。

如果你知道你正在循環遍歷的對象是在循環的時候計算出來,那麼這是一個惰性可迭代對象(lazy iterable)。

如果你知道你可以傳遞一些東西給 next 函數,它就是一個迭代器(這是最常見的惰性可迭代對象)。

如果你可以循環多次而不用「耗盡」它,它不是一個迭代器。如果你不能將某些東西傳遞給 next 函數,那麼它不是一個迭代器。 Python 3 的 range 對象不是迭代器。 如果你正在指導別人關於 range 對象的知識,請不要使用「迭代器」一詞,這會讓人十分困惑,並可能導致他人開始濫用「迭代器」這個詞。

原文:Python: range is not an iterator!

擴展閱讀:

  • 終於,SciPy 1.0 版發布了
  • 一個好的 README 的些許建議
  • 我們為什麼選擇用 Python 來開發 Quora
  • Python 家族有多龐大

極光日報,極光開發者旗下媒體。

每天導讀三篇英文技術文章。

推薦閱讀:

Kaggle HousePrice : LB 0.11666(前15%), 用搭積木的方式(2.實踐-特徵工程部分)
Python學習基礎知識小結
如何學習Python?
即將發布的 tornado 2.0 將會帶來哪些特性?
Python數據分析之jieba庫的運用

TAG:Python | Python入門 | Python開發 |