python迭代器與生成器
title: python迭代器與生成器
data: 2018-4-7
categories:
- python
tags: - python
迭代器
迭代器(Iterator)是訪問集合元素的一種方式。迭代器物件從集合的第一個元素開始訪問,直到所有的元素被訪問完結束。迭代器只能往前不會後退。
迭代器有兩個基本的方法:iter()
和 next()
python中對常見的迭代器使用場景是迴圈語句for,它用迭代器封裝集合,並且逐個訪問集合元素以執行迴圈體。比如:
for num in range(5):
print(num)
其中的range()返回一個包含所指定元素的集合,而for語句將其封裝成一個迭代器後訪問。
使用iter()呼叫可以將列表、集合轉換成迭代器,比如下面的 t 就是一個迭代器:
>>> mylist = [1,3,4,8,6,9]
>>> t = iter(mylist)
>>> print(t)
<listiterator object at 0x00000000025F39B0>
迭代器和普通python物件的區別是迭代器有一個next()方法,每次呼叫該方法可以放回一個元素。呼叫者(比如for語句)可以通過不斷呼叫next()方法來逐個訪問集合元素。比如:
>>> iter = iter(range(5)) >>> print iter.next() 0 >>> print iter.next() 1 >>> print iter.next() 2 ...
呼叫者可以一直這樣呼叫next()方法來訪問迭代器,直到next()返回StopIteration
異常表示迭代已經完成。
建立一個迭代器
把一個類作為一個迭代器使用需要在類中實現兩個方法 __iter__()
與 __next__()
。
Python 的建構函式為 __init__()
, 它會在物件初始化的時候執行。
__iter__()
方法返回一個特殊的迭代器物件, 這個迭代器物件實現了 __next__()
方法並通過 StopIteration
異常標識迭代的完成。
__next__()
方法(Python 2 裡是 next())會返回下一個迭代器物件。
建立一個返回數字的迭代器,初始值為 1,逐步遞增 1:
#python3
class MyNumbers:
def __iter__(self):
self.a = 1
return self
def __next__(self):
x = self.a
self.a += 1
return x
myclass = MyNumbers()
myiter = iter(myclass)
print(next(myiter))
print(next(myiter))
print(next(myiter))
print(next(myiter))
print(next(myiter))
執行輸出結果為:
1
2
3
4
5
StopIteration
StopIteration 異常用於標識迭代的完成,防止出現無限迴圈的情況,在 __next__()
方法中我們可以設定在完成指定迴圈次數後觸發 StopIteration
異常來結束迭代。
在 10 次迭代後停止執行:
#python3
class MyNumbers:
def __iter__(self):
self.a = 1
return self
def __next__(self):
if self.a <= 10:
x = self.a
self.a += 1
return x
else:
raise StopIteration
myclass = MyNumbers()
myiter = iter(myclass)
for x in myiter:
print(x)
執行輸出結果為:
1
2
3
4
5
6
7
8
9
10
生成器
在 Python 中,使用了 yield 的函式被稱為生成器(generator)。
跟普通函式不同的是,生成器是一個返回迭代器的函式,只能用於迭代操作,更簡單點理解生成器就是一個迭代器。
在呼叫生成器執行的過程中,每次遇到 yield 時函式會暫停並儲存當前所有的執行資訊,返回 yield 的值, 並在下一次執行 next() 方法時從當前位置繼續執行。
呼叫一個生成器函式,返回的是一個迭代器物件。
以下例項使用 yield 實現斐波那契數列:
#!/usr/bin/python3
import sys
def fibonacci(n): # 生成器函式 - 斐波那契
a, b, counter = 0, 1, 0
while True:
if (counter > n):
return
yield a
a, b = b, a + b
counter += 1
f = fibonacci(10) # f 是一個迭代器,由生成器返回生成
while True:
try:
print (next(f), end=" ")
except StopIteration:
sys.exit()
執行以上程式,輸出結果如下:
0 1 1 2 3 5 8 13 21 34 55
使用 yield
#!/usr/bin/python3
import sys
def fibonacci(n,w=0): # 生成器函式 - 斐波那契
a, b, counter = 0, 1, 0
while True:
if (counter > n):
return
yield a
a, b = b, a + b
print('%d,%d' % (a,b))
counter += 1
f = fibonacci(10,0) # f 是一個迭代器,由生成器返回生成
while True:
try:
print (next(f), end=" ")
except :
sys.exit()
輸出結果:
0 1,1
1 1,2
1 2,3
2 3,5
3 5,8
5 8,13
8 13,21
13 21,34
21 34,55
34 55,89
55 89,144
不使用 yield
#!/usr/bin/python3
import sys
def fibonacci(n,w=0): # 生成器函式 - 斐波那契
a, b, counter = 0, 1, 0
while True:
if (counter > n):
return
#yield a
a, b = b, a + b
print('%d,%d' % (a,b))
counter += 1
f = fibonacci(10,0) # f 是一個迭代器,由生成器返回生成
while True:
try:
print (next(f), end=" ")
except :
sys.exit()
輸出結果:
1,1
1,2
2,3
3,5
5,8
8,13
13,21
21,34
34,55
55,89
89,144
區別
第二種沒有yield時,函式只是簡單執行,沒有返回迭代器f。這裡的迭代器可以用生成l列表來理解一下:
>>> l = [i for i in range(0,15)]
>>> print(l)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
>>> m = (i for i in range(0,15))
>>> print(m)
<generator object <genexpr> at 0x104b6f258>
>>> for g in m:
... print(g,end=', ')
...
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
這裡的m就像上面的f一樣,是迭代器。
參考:http://www.runoob.com/python3/python3-iterator-generator.html 下面的筆記