理解Python的迭代器

2022-07-20 10:36:10 字數 4818 閱讀 5146

首先,廖雪峰老師的教程中解釋了迭代器和生成器,這篇文章只是補充和我個人的總結。

可以直接作用於for迴圈的物件統稱為可迭代物件(iterable)。

可以被next()函式呼叫並不斷返回下乙個值的物件稱為迭代器(iterator)。

所有的iterable均可以通過內建函式iter()來轉變為iterator。

對迭代器來講,有乙個__next__()就夠了。在你使用for 和 in 語句時,程式就會自動呼叫即將被處理的物件的迭代器物件,然後使用它的__next__()方法,直到監測到乙個stopiteration異常。

>>> l = [1,2,3]

>>> [x**2 for x in l]

[1, 4, 9]

>>> next(l)

traceback (most recent call last):

file "", line 1, in typeerror: 'list' object is not an iterator

>>> i=iter(l)

>>> next(i)

1>>> next(i)

2>>> next(i)

3>>> next(i)

traceback (most recent call last):

file "", line 1, in stopiteration

上面例子中,列表l可以被for進行迴圈但是不能被內建函式next()用來查詢下乙個值,所以l是iterable。

l通過iter進行包裝後設為i,i可以被next()用來查詢下乙個值,所以i是iterator。

題外話:

內建函式iter()僅僅是呼叫了物件的__iter__()方法,所以list物件內部一定存在方法__iter__()

內建函式next()僅僅是呼叫了物件的__next__()方法,所以list物件內部一定不存在方法__next__(),但是itrator中一定存在這個方法。

for迴圈內部事實上就是先呼叫iter()把iterable變成iterator在進行迴圈迭代的。

>>> l = [4,5,6]

>>> i = l.__iter__()

>>> l.__next__()

traceback (most recent call last):

file "", line 1, in attributeerror: 'list' object has no attribute '__next__'

>>> i.__next__()

4>>> from collections import iterator, iterable

>>> isinstance(l, iterable)

true

>>> isinstance(l, iterator)

false

>>> isinstance(i, iterable)

true

>>> isinstance(i, iterator)

true

>>> [x**2 for x in i]

[25, 36]

iterator繼承自iterable,從下面的測試中可以很方便的看到iterator包含__iter__()__next__()方法,而iteratble僅僅包含__iter__()

>>> from collections import iterator, iterable

>>> help(iterator)

help on class iterator:

class iterator(iterable)

| method resolution order:

| iterator

| iterable

| builtins.object

|**註解:從這裡可以看出iterable繼承自object, iterator繼承自iterable。

| methods defined here:

| | __iter__(self)

| | __next__(self)

| return the next item from the iterator. when exhausted, raise stopiteration

......

>>> help(iterable)

help on class iterable:

class iterable(builtins.object)

| methods defined here:

| | __iter__(self)

......

如果我們自己定義迭代器,只要在類裡面定義乙個__iter__()函式,用它來返回乙個帶__next__()方法的物件就夠了。

直接上**

class iterable:

def __iter__(self):

return iterator()

class iterator:

def __init__(self):

self.start=-1

def __next__(self):

self.start +=2

if self.start >10:

raise stopiteration

return self.start

i = iterable()

for i in i:

print(i)

上面的**實現的是找到10以內的奇數,**中的類名可以隨便取,不是一定需要使用我上面提供的類名的。

如果在iterator的__next__方法中沒有實現stopiteration異常,那麼則是表示的全部奇數,那麼需要在呼叫的時候設定退出迴圈的條件。

class iterable:

def __iter__(self):

return iterator()

class iterator:

def __init__(self):

self.start=-1

def __next__(self):

self.start +=2

return self.start

i = iterable()

for count, i in zip(range(5),i): #也可以用內建函式enumerate來實現計數工作。

print(i)

我們通過range來實現列印多少個元素,這裡表示列印5個元素,返回結果和上面一致。

當然,我們可以把這兩個類合併在一起,這樣實現程式的簡練。

最終版本如下

class iterable:

def __iter__(self):

return self

def __init__(self):

self.start=-1

def __next__(self):

self.start +=2

if self.start >10:

raise stopiteration

return self.start

i = iterable()

for i in i:

print(i)

迭代器是一次性消耗品,使用完了以後就空了,請看。

>>> l=[1,2,3]

>>> i=iter(l)

>>> for i in i:

... print(i, end='-')

...1-2-3-

>>>next(i)

traceback (most recent call last):

file "", line 1, in stopiteration

當迴圈以後就殆盡了,再次使用呼叫時會引發stopiteration異常。

我們想通過直接賦值的形式把迭代器儲存起來,可以下次使用。

但是通過下面的範例可以看出來,根本不管用。

>>> i=iter(l)

>>> j=i

>>> next(i)

1>>> next(j)

2>>> next(i)

3>>> next(j)

traceback (most recent call last):

file "", line 1, in stopiteration

那怎麼樣才能達到我們要的效果呢?

我們需要使用copy包中的deepcopy了,請看下面:

>>> import copy

>>> i=iter(l)

>>> j=copy.deepcopy(i)

>>> next(i)

1>>> next(i)

2>>> next(j)

1

補充:迭代器不能向後移動, 不能回到開始。

所以需要做一些特殊的事情才能實現向後移動等功能。

以上**均在python 3.4 中測試通過。

日誌:8月13日完成

8月14日新增關於iterator, iterable的更多解釋在題外話的第4點。

python迭代器簡單理解

1 凡是可應用於for迴圈的物件都是可迭代 可迴圈 iterable 物件,例如字串 列表 元組 字典 集合等 2 凡是可應用於next 方法的物件都是迭代器 iterator 物件,迭代器 iterator 是乙個惰性計算的過程,只有在需要返回下乙個數值的時候才會被計算 這一過程跟生成器很像,都是...

簡單理解Python迭代器

在使用列表時,直接將資料存入列表將會佔據大量空間,且復用率較低,為解決這個問題,這裡了解一下迭代器,從而建立一種資料產生的方式,以此來節省空間。注意,這裡需要使用到內建函式 iter 簡單理解為,使用了 iter 才會是乙個可迭代物件,關於這部分,我們可以對一些物件做一些判斷,從而清楚是不是可迭代物...

python的迭代器 Python 迭代器

迭代器 迭代是訪問集合元素的一種方式。迭代器是乙個可以記住遍歷的位置的物件。迭代器物件從集合的第乙個元素開始訪問,直到所有的元素被訪問完結束。迭代器只能往前不會後退。可迭代物件 以直接作用於 for 迴圈的資料型別有以下幾種 一類是集合資料型別,如 list tuple dict set str 等...