1. 程式人生 > >python 迭代器 生成器

python 迭代器 生成器

1. 迭代器

      迭代器是訪問集合元素的一種方式。迭代器物件從集合的第一個元素開始訪問,知道所有的元素被訪問完結束。迭代器只能往前不會後退,不過這也沒什麼,因為人們很少在迭代途中往後退。

1.1 使用迭代器的優點

      對於原生支援隨機訪問的資料結構(如tuple、list),迭代器和經典for迴圈的索引訪問相比並無優勢,反而丟失了索引值(可以使用內建函式enumerate()找回這個索引值)。但對於無法隨機訪問的資料結構(比如set)而言,迭代器是唯一的訪問元素的方式。

      另外,迭代器的一大優點是不要求事先準備好整個迭代過程中所有的元素。迭代器僅僅在迭代到某個元素時才計算該元素,而在這之前或之後,元素可以不存在或者被銷燬。這個特點使得它特別適合用於遍歷一些巨大的或是無限的集合,比如幾個G的檔案,或是斐波那契數列等等。

      迭代器更大的功勞是提供了一個統一的訪問集合的介面,只要定義了__iter__()方法物件,就可以使用迭代器訪問。

迭代器有兩個基本的方法

  • next方法:返回迭代器的下一個元素
  • __iter__方法:返回迭代器物件本身

下面用生成斐波那契數列為例子,說明為何用迭代器

程式碼1

 def fab(max): 
    n, a, b = 0, 0, 1 
    while n < max: 
        print b 
        a, b = b, a + b 
        n = n + 1

直接在函式fab(max)中用print列印會導致函式的可複用性變差,因為fab返回None。其他函式無法獲得fab函式返回的數列。

程式碼2

 def fab(max): 
    L = []
    n, a, b = 0, 0, 1 
    while n < max: 
        L.append(b) 
        a, b = b, a + b 
        n = n + 1
    return L

程式碼2滿足了可複用性的需求,但是佔用了記憶體空間,最好不要。

程式碼3

對比

 for i in range(1000): pass
 for i in xrange(1000): pass

前一個返回1000個元素的列表,而後一個在每次迭代中返回一個元素,因此可以使用迭代器來解決複用可佔空間的問題

 class Fab(object): 
    def __init__(self, max): 
        self.max = max 
        self.n, self.a, self.b = 0, 0, 1 

    def __iter__(self): 
        return self 

    def next(self): 
        if self.n < self.max: 
            r = self.b 
            self.a, self.b = self.b, self.a + self.b 
            self.n = self.n + 1 
            return r 
        raise StopIteration()

執行

>>> for key in Fabs(5):
	print key

	
1
1
2
3
5

Fabs 類通過 next() 不斷返回數列的下一個數,記憶體佔用始終為常數  

1.2 使用迭代器

使用內建的工廠函式iter(iterable)可以獲取迭代器物件:

>>> lst = range(5)
>>> it = iter(lst)
>>> it
<listiterator object at 0x01A63110>

使用next()方法可以訪問下一個元素:

>>> it.next()
0
>>> it.next()
1
>>> it.next()
2

python處理迭代器越界是丟擲StopIteration異常

>>> it.next()
3
>>> it.next
<method-wrapper 'next' of listiterator object at 0x01A63110>
>>> it.next()
4
>>> it.next()

Traceback (most recent call last):
  File "<pyshell#27>", line 1, in <module>
    it.next()
StopIteration

瞭解了StopIteration,可以使用迭代器進行遍歷了

lst = range(5)
it = iter(lst)
try:
    while True:
        val = it.next()
        print val
except StopIteration:
    pass

結果

>>> 
0
1
2
3
4

事實上,因為迭代器如此普遍,python專門為for關鍵字做了迭代器的語法糖。在for迴圈中,Python將自動呼叫工廠函式iter()獲得迭代器,自動呼叫next()獲取元素,還完成了檢查StopIteration異常的工作。如下

>>> a = (1, 2, 3, 4)
>>> for key in a:
    print key

    
1
2
3
4

首先python對關鍵字in後的物件呼叫iter函式迭代器,然後呼叫迭代器的next方法獲得元素,直到丟擲StopIteration異常。

1.3 定義迭代器

下面一個例子——斐波那契數列

# -*- coding: cp936 -*-
class Fabs(object):
    def __init__(self,max):
        self.max = max
        self.n, self.a, self.b = 0, 0, 1  #特別指出:第0項是0,第1項是第一個1.整個數列從1開始
    def __iter__(self):
        return self
    def next(self):
        if self.n < self.max:
            r = self.b
            self.a, self.b = self.b, self.a + self.b
            self.n = self.n + 1
            return r
        raise StopIteration()

print Fabs(5)
for key in Fabs(5):
    print key
    

結果

<__main__.Fabs object at 0x01A63090>
1
1
2
3
5

2. 生成器

      帶有 yield 的函式在 Python 中被稱之為 generator(生成器),幾個例子說明下(還是用生成斐波那契數列說明)

可以看出程式碼3遠沒有程式碼1簡潔,生成器(yield)既可以保持程式碼1的簡潔性,又可以保持程式碼3的效果

程式碼4 

def fab(max):
    n, a, b = 0, 0, 1
    while n < max:
        yield b
        a, b = b, a + b
        n = n + 1

執行

>>> for n in fab(5):
	print n

	
1
1
2
3
5

      簡單地講,yield 的作用就是把一個函式變成一個 generator,帶有 yield 的函式不再是一個普通函式,Python 直譯器會將其視為一個 generator,呼叫 fab(5) 不會執行 fab 函式,而是返回一個 iterable 物件!在 for 迴圈執行時,每次迴圈都會執行 fab 函式內部的程式碼,執行到 yield b 時,fab 函式就返回一個迭代值,下次迭代時,程式碼從 yield b 的下一條語句繼續執行,而函式的本地變數看起來和上次中斷執行前是完全一樣的,於是函式繼續執行,直到再次遇到 yield。看起來就好像一個函式在正常執行的過程中被 yield 中斷了數次,每次中斷都會通過 yield 返回當前的迭代值。

也可以手動呼叫 fab(5) 的 next() 方法(因為 fab(5) 是一個 generator 物件,該物件具有 next() 方法),這樣我們就可以更清楚地看到 fab 的執行流程:

>>> f = fab(3)
>>> f.next()
1
>>> f.next()
1
>>> f.next()
2
>>> f.next()

Traceback (most recent call last):
  File "<pyshell#62>", line 1, in <module>
    f.next()
StopIteration

return作用

在一個生成器中,如果沒有return,則預設執行到函式完畢;如果遇到return,如果在執行過程中 return,則直接丟擲 StopIteration 終止迭代。例如

>>> s = fab(5)
>>> s.next()
1
>>> s.next()

Traceback (most recent call last):
  File "<pyshell#66>", line 1, in <module>
    s.next()
StopIteration

程式碼5  檔案讀取

 def read_file(fpath): 
    BLOCK_SIZE = 1024 
    with open(fpath, 'rb') as f: 
        while True: 
            block = f.read(BLOCK_SIZE) 
            if block: 
                yield block 
            else: 
                return

如果直接對檔案物件呼叫 read() 方法,會導致不可預測的記憶體佔用。好的方法是利用固定長度的緩衝區來不斷讀取檔案內容。通過 yield,我們不再需要編寫讀檔案的迭代類,就可以輕鬆實現檔案讀取。

3. 參考

相關推薦

python~,生成器

可迭代物件: 以直接作用於 for 迴圈的資料型別有以下幾種: 一類是集合資料型別,如 list 、 tuple 、 dict 、 set 、 str 等 一類是 generator ,包括生成器和帶 yield 的generator function 這些可以直接作用於 for 迴

python~,生成器(3)

生成器   通過列表生成式,我們可以直接建立一個列表。但是,受到記憶體限制,列表容量肯定是有限的。而且,建立一個包含100萬個元素的列表,不僅佔用很大的儲存空間,如果我們僅僅需要訪問前面幾個元素,那後面絕大多數元素佔用的空間都白白浪費了。所以,如果列表元素可以按照某種演算法推算出來,那

python~,生成器(2)

**生成器一定是迭代器,但是迭代器不一定是生成器 迭代器: 可以被next()函式呼叫並不斷返回下一個值的物件稱為迭代器:Iterator ??isinstance() 判斷一個物件是否是 Iterator 物件: In [56]: from collections import I

python-生成器-列表推導式-生成器表示式-day11-12

生成器Generator    生成器函式一個包含yield關鍵字的函式就是一個生成器函式。yield可以為我們從函式中返回值,但是yield又不同於return,return的執行意味著程式的結束,呼叫生成器函式不會得到返回的具體的值,而是得到一個可迭代的物件。每一次獲取這個可

python&生成器使用技巧(1):遍歷、代理、生成器建立、反向

1. 手動遍歷迭代器 next() 遍歷一個可迭代物件中的所有元素,但是卻不想使用for迴圈。為了手動的遍歷可迭代物件,使用 next() 函式並在程式碼中捕獲 StopIteration 異常。 通常來講, StopIteration 用來指示迭代的結尾。 然而,如果手動

python&生成器使用技巧(2):切片、遍歷、索引值、多序列、多容器物件

1. 迭代器切片 迭代器和生成器不能使用標準的切片操作,因為它們的長度事先並不知道(並且也沒有實現索引)。 函式 islice() 返回一個可以生成指定元素的迭代器,通過遍歷並丟棄直到切片開始索引位置的所有元素,然後開始一個個的返回元素,並直到切片結束索引位置。 impo

4.python生成器裝飾

基本概念 1.容器(container) 容器是一種把多個元素組織在一起的資料結構,容器中的元素可以逐個地迭代獲取,可以用in, not in關鍵字判斷元素是否包含在容器中。通常這類資料結構把所有的元素儲存在記憶體中(也有一些特例,並不是所有的元素都放在記憶體,比如迭代器和生成器物件)在Python中

python 生成器

1. 迭代器       迭代器是訪問集合元素的一種方式。迭代器物件從集合的第一個元素開始訪問,知道所有的元素被訪問完結束。迭代器只能往前不會後退,不過這也沒什麼,因為人們很少在迭代途中往後退。 1.1 使用迭代器的優點       對於原生支援隨機訪問的資料結構(如tuple、list),迭代器和經典

python 生成器 生成器表示式

生成器Generator 是建立迭代器的簡單而強大的工具。它們寫起來就像是正規的函式,需要返回資料的時候使用 yield 語句。每次 next() 被呼叫時,生成器回覆它脫離的位置(它記憶語句最後一次執行的位置和所有的資料值)。以下示例演示了生成器可以很簡單的創建出來:def reverse(data):

PythonIterator和生成器generator

容器(container) 容器是一種把多個元素組織在一起的資料結構,容器中的元素可以逐個地迭代獲取,可以用in, not in關鍵字判斷元素是否包含在容器中。通常這類資料結構把所有的元素儲存在記憶體中(也有一些特例,並不是所有的元素都放在記憶體,比如迭代器和生成器物件) 可迭代物

python生成器和裝飾

文章目錄 生成器 生成器表示式(generator expression) 通過使用yield關鍵字定義 迭代器 迭代器概述 iter()函式 建立迭代器 建立一個迭代器(類) 內建迭代器

python 生成器詳解。

迭代器 任何實現了__iter__和__next__()(python2中實現next())方法的物件都是迭代器 迭代器可以被next()函式呼叫並不斷返回下一個值的,或者使用for迴圈。 因為Python的for迴圈本質上就是通過不斷呼叫next()函式實現的。 for 迴圈在處理這些

python(生成器

迭代器 :(列表,元組,字典,集合,字串,檔案) 迭代:每次重複的過程成為迭代的過程,每次迭代得到的結果,回作為下次迭代的初始值 迭代器:可以被next()函式呼叫並不斷返回下一個值的物件稱為迭代器 它只是實現了__next__()方法的物件,並不是容器 Iter()(iteration

3、【PythonPython 3入門(流程控制//生成器/函式/變數作用域)

一、流程控制 1、if 控制 if 表示式1: 語句 if 表示式2: 語句 elif 表示式3: 語句 else: 語句 elif 表示式4: 語句 else: 語句     1、

Python記錄12:+生成器+生成式

'''1. 什麼是迭代器 什麼是迭代:迭代就是一個重複的過程,但是每一次重複都是基於上一次的結果而進行的 單純的重複不是迭代: while True: print(1) 迭代的過程 l=['a','b','c'] i=0 while i < len(l): pr

Python基礎【生成式 | | 生成器

生成式 列表生成式 快速生成具有特定規律的列表 普通寫法:even=[]for i in range(100):if i%2==0:even.append(i) 列表生成式形式:even=[i for i in range(100) if i%2==0] ##生成0-99之間

Python 物件, , 生成器

容器 容器是一種把多個元素組織在一起的資料結構, 容器中的元素可以逐個地迭代獲取. 如: list, set, dict, tuple, str 可迭代物件 可以返回一個迭代器的物件. x = [1,2,3] y = iter(x) z = iter(x) x

python進階之 , 生成器

練習: 說出如下程式碼的列印結果 >>> def foo(): … print(111) … yield 222 … print(333) … yield 444 … print(555) >>&g

python生成器差別

生成器是一類特殊的迭代器,在迴圈遍歷自定義容器物件時,會使用python內建函式iter()呼叫遍歷物件的_iter_(self)獲得一個迭代器,之後再迴圈對這個迭代器使用next()呼叫迭代器物件的_next_(self) 實現生成器的功能。 python中生成器和迭代器

python生成器詳解

前文   迭代器(Iterator)和生成器(generator)是python眾多強大的資料型別之一,兩者的作用都是惰性計算,即不會立即產生所有結果,而是逐步產生一個個;兩者的區別則是生成器本質上屬於迭代器,生成器用於“憑空”生成元素,迭代器則是用於從集合中取