1. 程式人生 > >Python中的迭代器iterator和yield生成器(constructor)

Python中的迭代器iterator和yield生成器(constructor)

什麼叫迭代器和可迭代物件?

一、可迭代物件(Iterable)

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

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

然後使用它的next()方法呼叫,直到監測到一個StopIteration異常。

a = [1, 2, 3, 4]
b = iter(a)
print b.next()
print b.next()
print b.next()
print b.next()
print b.next()

顯示結果為:

1

2

3

4

Traceback (most recent call last):

File “C:/workspace2/secAuto_flask/test3.py”, line 13, in

print b.next()

StopIteration

二、迭代器(iterator)

迭代器是一個實現了迭代器協議的物件,在Python中,支援迭代器協議就是實現物件的__iter__()和next()方法。其中iter()方法返回迭代器物件本身;next()方法返回容器的下一個元素,在結尾時引發StopIteration異常。

其實,當我們使用for語句的時候,for語句就會自動的通過iter()方法來獲得迭代器物件,並且通過next()方法來獲取下一個元素。

看看我們自定義的迭代器:

class MyIterator(object):
    def __init__(self, n):
        self.index = 0
        self.n = n

    def __iter__(self):
        return self

    def next(self):
        if self.index < self.n:
            var = self.index
            self.index += 1
            return var
        else:
            raise StopIteration

for的呼叫方式:

myRange = MyIterator(3)
for i in myRange:
    print i

next的呼叫方式:

myRange = MyIterator(3)
print myRange.next()
print myRange.next()
print myRange.next()

這兩種方式顯示的結果:

0

1

2

使用迭代器一個顯而易見的好處就是:每次只從物件中讀取一條資料,不會造成記憶體的過大開銷

比如要逐行讀取一個檔案的內容,利用readlines()方法,我們可以這麼寫:

for line in open("test.txt").readlines():
print line

這樣雖然可以工作,但不是最好的方法。因為他實際上是把檔案一次載入到記憶體中,然後逐行列印。當檔案很大時,這個方法的記憶體開銷就很大了。

利用file的迭代器,我們可以這樣寫:

for line in open("test.txt"):   #use file iterators
print line

這是最簡單也是執行速度最快的寫法,他並沒顯式的讀取檔案,而是利用迭代器每次讀取下一行。

二、生成器(constructor)

生成器函式在Python中與迭代器協議的概念聯絡在一起。簡而言之,包含yield語句的函式會被特地編譯成生成器。當函式被呼叫時,他們返回一個生成器物件,這個物件支援迭代器介面。函式也許會有個return語句,但它的作用是用來yield產生值的。

不像一般的函式會生成值後退出,生成器函式在生成值後會自動掛起並暫停他們的執行和狀態,他的本地變數將儲存狀態資訊,這些資訊在函式恢復時將再度有效

def g(n):
    for i in range(n):
        yield i **2

for i in g(5):
    print i,":",

顯示的結果:

0 : 1 : 4 : 9 : 16 :

要了解他的執行原理,我們來用next方法看看:

t=g(5)
print t.next()
print t.next()
print t.next()
print t.next()
print t.next()
print t.next()

顯示結果為:

0

1

4

9

16

Traceback (most recent call last):

File “

利用yield從序列中移除重複項,切儲存元素順序不變

def dedupe(items, key=True):
    seen = set()
    for item in items:
        var = item if key else key(item)
        if var not in seen:
            yield item
            seen.add(var)


a = [1, 2, 6, 3, 2, 4, 5, 3, 6]
b = list(dedupe(a))
print b