1. 程式人生 > >Python迭代器,可迭代物件,生成器

Python迭代器,可迭代物件,生成器

1. 迭代器

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

  • 1.1 使用迭代器的優點
    對於原生支援隨機訪問的資料結構(如tuple、list),迭代器和經典for迴圈的索引訪問相比並無優勢,反而丟失了索引值(可以使用內建函式enumerate()找回這個索引值)。但對於無法隨機訪問的資料結構(比如set)而言,迭代器是唯一的訪問元素的方式。
    另外,迭代器的一大優點是不要求事先準備好整個迭代過程中所有的元素。迭代器僅僅在迭代到某個元素時才計算該元素,而在這之前或之後,元素可以不存在或者被銷燬。這個特點使得它特別適合用於遍歷一些巨大的或是無限的集合,比如幾個G的檔案,或是斐波那契數列等等。
    迭代器更大的功勞是提供了一個統一的訪問集合的介面,只要定義了iter

    ()方法物件,就可以使用迭代器訪問。

    迭代器有兩個基本的方法

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

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

#程式碼1:直接在函式fab(max)中用print列印會導致函式的可複用性變差,因為fab返回None。其他函式無法獲得fab函式返回的數列。
def fab(max): 
    n, a, b = 0, 0, 1 
    while n < max: 
        print b 
        a, b = b, a + b 
        n = n + 1
#程式碼2:程式碼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
#程式碼3:
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,我們不再需要編寫讀檔案的迭代類,就可以輕鬆實現檔案讀取。

#
#
#
#
#
#
#

http://www.cnblogs.com/wswang/p/6047994.html
也就是說迭代器類似於一個遊標,卡到哪裡就是哪裡,可以通過這個來訪問某個可迭代物件的元素;同時,也不是隻有Python有這個特性。比如C++的STL中也有這個,如vector::iterator it。下面主要說一下Python中的可迭代物件和迭代器吧。

  • Python可迭代物件(Iterable)
    Python中經常使用for來對某個物件進行遍歷,此時被遍歷的這個物件就是可迭代物件,像常見的list,tuple都是。如果給一個準確的定義的話,就是隻要它定義了可以返回一個迭代器的__iter__方法,或者定義了可以支援下標索引的__getitem__方法(這些雙下劃線方法會在其他章節中全面解釋),那麼它就是一個可迭代物件。
  • Python迭代器(iterator)
    迭代器是通過next()來實現的,每呼叫一次他就會返回下一個元素,當沒有下一個元素的時候返回一個StopIteration異常,所以實際上定義了這個方法的都算是迭代器。可以用通過下面例子來體驗一下迭代器:
In [38]: s = 'ab'

In [39]: it = iter(s)

In [40]: it
Out[40]: <iterator at 0x1068e6d50>

In [41]: print it
<iterator object at 0x1068e6d50>

In [42]: it.next()
Out[42]: 'a'

In [43]: it.next()
Out[43]: 'b'

In [44]: it.next()
---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-44-54f0920595b2> in <module>()
----> 1 it.next()

StopIteration:

自己實現一個迭代器,如下(參見官網文件):

class Reverse:
    """Iterator for looping over a sequence backwards."""
    def __init__(self, data):
        self.data = data
        self.index = len(data)

    def __iter__(self):
        return self

    def next(self):
        if self.index == 0:
            raise StopIteration
        self.index = self.index - 1
        return self.data[self.index]

rev = Reverse('spam')
for char in rev:
    print char

[output]
m
a
p
s
  • 生成器(Generators)
    生成器是構造迭代器的最簡單有力的工具,與普通函式不同的只有在返回一個值的時候使用yield來替代return,然後yield會自動構建好next()iter()。是不是很省事。例如:
def reverse(data):
    for index in range(len(data)-1, -1, -1):
        yield data[index]

>>> for char in reverse('golf'):
...     print char
...
f
l
o
g

生成器最佳應用場景是:你不想同一時間將所有計算出來的大量結果集分配到記憶體當中,特別是結果集裡還包含迴圈。比方說,迴圈列印1000000個數,我們一般會使用xrange()而不是range(),因為前者返回的是生成器,後者返回的是列表(列表消耗大量空間)。

相關推薦

搞清楚 Python物件生成器

很多夥伴對 Python 的迭代器、可迭代物件、生成器這幾個概念有點搞不清楚,我來說說我的理解,希望對需要的朋友有所幫助。 1 迭代器協議 迭代器協議是核心,搞懂了這個,上面的幾個概念也就很好理解了。 所謂迭代器協議,就是要求一個迭代器必須要實現如下兩個方法 iterator.__iter__(

python物件

迭代器 定義:能夠使用for-in進行遍歷,並且能夠使用next依次獲取其中一個元素。 說明: 生成器就是一種特殊的迭代器 判斷一個物件是不是迭代器 from collections import Iterator # lt

Python物件生成器

1、什麼叫迭代 現在,我們已經獲得了一個新線索,有一個叫做“可迭代的”概念。 首先,我們從報錯來分析,好像之所以1234不可以for迴圈,是因為它不可迭代。那麼如果“可迭代”,就應該可以被for迴圈了。 這個我們知道呀,字串、列表、元組、字典、集合都可以被for迴圈,說明他們都是可迭代的

Python生成器物件 的概念

生成器 在 Python 中,一邊迴圈一邊計算的機制,稱為 生成器(generator) 可以通過 next() 函式獲得 generator 的下一個返回值 生成器 的兩種表示方法: 1、將列表生成式的 [ ] 改為 ( ) [2*x for x

物件

基於python3 迭代器 = 可迭代的物件 可迭代的物件 != 迭代器 講在前面: 返回迭代器的物件,有:open(), map(), zip()和filte()函式,這幾個函式直接返回迭代器也就是可以直接在結果中呼叫next 如: f = open('xxx.txt')

物件生成器

  迭代器與可迭代物件 1、定義: 可迭代物件:大部分容器如 list,truples,str,sets是可迭代物件,但是他們不是迭代器。可迭代物件實現了__iter__方法,返回一個迭代器,或者使用iter(“可迭代物件”)返回一個迭代器。   迭代器:迭代器提供了一

【ES6】物件

ES6 新的陣列方法、集合、for-of 迴圈、展開運算子(...)甚至非同步程式設計都依賴於迭代器(Iterator )實現。本文會詳解 ES6 的迭代器與生成器,並進一步挖掘可迭代物件的內部原理與使用方法 一、迭代器的原理 在程式語言中處理陣列或集合時,使用迴圈語句必須要初始化一個變數記錄迭

列表解析式、生成器物件的區別和應用

導文 語法糖(Syntactic sugar) 列表生成式(list comprehension) 生成器(generator) 迭代器(iterator) 可迭代物件(iterable) Iterable、Iterator與Generator之間的關係

python對象

try 而且 clas style 是我 ble 但是 加載 instance 叠代器一定是可叠代對象,但是可叠代對象不一定是叠代器。 list,truple,str這些都是可叠代對象,但是他們不一定是叠代器。叠代器本身不知道自己要執行多少次,所以可以理解為不知道有多少個

python生成器與叠對象

但是 class 進行 避免異常 示例代碼 iterable 打印 iterator 同時 來簡單的說下python中的生成器和可叠代對象以及叠代器的問題。只是簡單地記錄一下並不涉及太深入的內容。 首先來說一下什麽是生成器,先看下面的代碼: 1 #_*_ coding:u

_對象_生成器

port yield iter() als ins typeerror tor list collect [可叠代對象]保存的是已經生成好的數據,占用大量的空間有__iter__方法 就是可叠代對象(Iterable) [叠代器]保存的是生成數據的方法,占用極小的空間,需

對象與生成器

for instance ron 地方 我們 app ont generator 大數據 Iterator 與 gerater的作用是優化內存,當處理大文件,大數據的時候可以使用。   1. 對大列表進行優化   2. 大文件的優化 一、基本概念 叠代器:  一種數

python物件生成器理解

上篇文章, python itertools 裡面實現的groupby方法。裡面用到了object, id, iter等很基礎的方法, 看的有點暈。這裡重新整理一下迭代器,可迭代物件, 生成器。複習一下,加深印象。 python語言很容易上手。比如for迴圈。 a = [1, 2,

python中的生成器物件

最近學習了python中的生成器、迭代器、可迭代物件的知識,現在回顧一下,鞏固理解 先說一下列表生成式: 執行結果如下: 通過方括號加入裡面的表示式,從而生成一個列表,在這裡注意一下,列表生成時也可以加入函式: 結果如下:   計算了X的三次方

python物件生成器--

python迭代 給定一個list或tuple,我們可以通過for迴圈來遍歷這個list或tuple,這種遍歷我們稱為迭代(Iteration) 可迭代物件: List:for a in List dict:(因為dict的儲存不是按照list的方式順序

Python物件生成器

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

物件生成器區別

迭代物件 :實現__iter__方法,返回迭代器。不需要顯示繼承Iterable, 迭代器: 實現_iter__方法,__next__方法,不需要顯示繼承Iterator from collections import Iterable,Iterator def generator():

Pythoh 物件容器生成器

容器一般都是可迭代物件,是一種資料結構(data structure)。很多容器(list,dict,tuple)都是可迭代物件。但是可迭代物件不一定是一種資料結構,比如開啟的檔案或者sockets。可迭代物件可以(can)返回迭代器。每一個可迭代物件在程式碼都實現了__it

Python3學習(8)--的和

開始本篇之前,我們先來了解幾個單詞         迭代:iteration 可迭代的:Iterable     迭代器:iterator 從單詞我們可以看出來差異,可迭代的一看就是狀態詞,我們不做多說,下面會再講,而我們發現迭代和迭代器都是一個名詞表示,只不過迭代相比較

list的能解決併發問題,collection 的不能解決併發問題for可以解決併發問題

list的迭代器能解決併發問題,collection 的迭代器不能解決併發問題   為什麼list支援add,collection不支援   例如有兩個人同時新增第三個元素 list的迭代器能鎖定執行緒 只有等第一人新增完成才能進行第二個人新增 而 collection的迭代器卻不