首先,廖雪峰老師的教程中解釋了迭代器和生成器,這篇文章只是補充和我個人的總結。
可以直接作用於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 等...