在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ Python/ 迭代器 (Iterator)
基礎(chǔ)
itertools
HTTP 服務(wù)
hashlib
閉包
文件和目錄
單元測(cè)試
使用 @property
標(biāo)準(zhǔn)模塊
陌生的 metaclass
Base64
進(jìn)程、線程和協(xié)程
讀寫二進(jìn)制文件
匿名函數(shù)
輸入和輸出
Click
元組
字符編碼
partial 函數(shù)
參考資料
collections
協(xié)程
類和實(shí)例
Python 之旅
定制類和魔法方法
常用數(shù)據(jù)類型
繼承和多態(tài)
ThreadLocal
HTTP 協(xié)議簡(jiǎn)介
Requests 庫(kù)的使用
讀寫文本文件
列表
os 模塊
迭代器 (Iterator)
正則表達(dá)式
集合
上下文管理器
異常處理
你不知道的 super
定義函數(shù)
datetime
資源推薦
字典
slots 魔法
hmac
第三方模塊
進(jìn)程
類方法和靜態(tài)方法
函數(shù)參數(shù)
高階函數(shù)
函數(shù)
re 模塊
高級(jí)特性
線程
argparse
生成器
結(jié)束語(yǔ)
字符串
map/reduce/filter
函數(shù)式編程
Celery
裝飾器

迭代器 (Iterator)

迭代和可迭代

迭代器這個(gè)概念在很多語(yǔ)言中(比如 C++,Java)都是存在的,但是不同語(yǔ)言實(shí)現(xiàn)迭代器的方式各不相同。在 Python 中,迭代器是指遵循迭代器協(xié)議(iterator protocol)的對(duì)象。至于什么是迭代器協(xié)議,稍后自然會(huì)說明。為了更好地理解迭代器,我先介紹和迭代器相關(guān)的兩個(gè)概念:

  • 迭代(Iteration)
  • 可迭代對(duì)象(Iterable)

你可能會(huì)覺得這是在玩文字游戲,但這確實(shí)是要搞清楚的。

當(dāng)我們用一個(gè)循環(huán)(比如 for 循環(huán))來(lái)遍歷容器(比如列表,元組)中的元素時(shí),這種遍歷的過程就叫迭代。

在 Python 中,我們使用 for...in... 進(jìn)行迭代。比如,遍歷一個(gè) list:

numbers = [1, 2, 3, 4]
for num in numbers:
    print num

像上面這種可以使用 for 循環(huán)進(jìn)行迭代的對(duì)象,就是可迭代對(duì)象,它的定義如下:

含有 __iter__() 方法或 __getitem__() 方法的對(duì)象稱之為可迭代對(duì)象。

我們可以使用 Python 內(nèi)置的 hasattr() 函數(shù)來(lái)判斷一個(gè)對(duì)象是不是可迭代的:

>>> hasattr((), '__iter__')
True
>>> hasattr([], '__iter__')
True
>>> hasattr({}, '__iter__')
True
>>> hasattr(123, '__iter__')
False
>>> hasattr('abc', '__iter__')
False
>>> hasattr('abc', '__getitem__')
True

另外,我們也可使用 isinstance() 進(jìn)行判斷:

>>> from collections import Iterable

>>> isinstance((), Iterable)        # 元組
True
>>> isinstance([], Iterable)        # 列表
True
>>> isinstance({}, Iterable)        # 字典
True
>>> isinstance('abc', Iterable)     # 字符串
True
>>> isinstance(100, Iterable)       # 數(shù)字
False

可見,我們熟知的字典(dict)、元組(tuple)、集合(set)和字符串對(duì)象都是可迭代的。

迭代器

現(xiàn)在,讓我們看看什么是迭代器(Iterator)。上文說過,迭代器是指遵循迭代器協(xié)議(iterator protocol)的對(duì)象。從這句話我們可以知道,迭代器是一個(gè)對(duì)象,但比較特別,它需要遵循迭代器協(xié)議,那什么是迭代器協(xié)議呢?

迭代器協(xié)議(iterator protocol)是指要實(shí)現(xiàn)對(duì)象的 __iter()__next() 方法(注意:Python3 要實(shí)現(xiàn) __next__() 方法),其中,__iter()__ 方法返回迭代器對(duì)象本身,next() 方法返回容器的下一個(gè)元素,在沒有后續(xù)元素時(shí)拋出 StopIteration 異常。

接下來(lái)講講迭代器的例子,有什么常見的迭代器呢?列表是迭代器嗎?字典是迭代器嗎?我們使用 hasattr() 進(jìn)行判斷:

>>> hasattr((1, 2, 3), '__iter__')
True
>>> hasattr((1, 2, 3), 'next')  # 有 __iter__ 方法但是沒有 next 方法,不是迭代器
False
>>>
>>> hasattr([1, 2, 3], '__iter__')
True
>>> hasattr([1, 2, 3], 'next')
False
>>>
>>> hasattr({'a': 1, 'b': 2}, '__iter__')
True
>>> hasattr({'a': 1, 'b': 2}, 'next')
False

同樣,我們也可以使用 isinstance() 進(jìn)行判斷:

>>> from collections import Iterator
>>>
>>> isinstance((), Iterator)
False
>>> isinstance([], Iterator)
False
>>> isinstance({}, Iterator)
False
>>> isinstance('', Iterator)
False
>>> isinstance(123, Iterator)
False

可見,雖然元組、列表和字典等對(duì)象是可迭代的,但它們卻不是迭代器!對(duì)于這些可迭代對(duì)象,可以使用 Python 內(nèi)置的 iter() 函數(shù)獲得它們的迭代器對(duì)象,看下面的使用:

>>> from collections import Iterator
>>> isinstance(iter([1, 2, 3]), Iterator)  # 使用 iter() 函數(shù),獲得迭代器對(duì)象
True
>>> isinstance(iter('abc'), Iterator)
True
>>>
>>> my_str = 'abc'
>>> next(my_str)      # my_str 不是迭代器,不能使用 next(),因此出錯(cuò)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-15-5f369cd8082f> in <module>()
----> 1 next(my_str)

TypeError: str object is not an iterator
>>>
>>> my_iter = iter(my_str)   # 獲得迭代器對(duì)象
>>> isinstance(my_iter, Iterator)
True
>>> next(my_iter)   # 可使用內(nèi)置的 next() 函數(shù)獲得下一個(gè)元素
'a'

事實(shí)上,Python 的 for 循環(huán)就是先通過內(nèi)置函數(shù) iter() 獲得一個(gè)迭代器,然后再不斷調(diào)用 next() 函數(shù)實(shí)現(xiàn)的,比如:

for x in [1, 2, 3]:
    print i

等價(jià)于

# 獲得 Iterator 對(duì)象
it = iter([1, 2, 3])

# 循環(huán)
while True:
    try:
        # 獲得下一個(gè)值
        x = next(it)
        print x
    except StopIteration:
        # 沒有后續(xù)元素,退出循環(huán)
        break

斐波那契數(shù)列迭代器

現(xiàn)在,讓我們來(lái)自定義一個(gè)迭代器:斐波那契(Fibonacci)數(shù)列迭代器。根據(jù)迭代器的定義,我們需要實(shí)現(xiàn) __iter()__next() 方法(在 Python3 中是 __next__() 方法)。先看代碼:

# -*- coding: utf-8 -*-

from collections import Iterator

class Fib(object):
    def __init__(self):
        self.a, self.b = 0, 1

    # 返回迭代器對(duì)象本身
    def __iter__(self):
        return self

    # 返回容器下一個(gè)元素
    def next(self):
        self.a, self.b = self.b, self.a + self.b
        return self.a

def main():
    fib = Fib()    # fib 是一個(gè)迭代器
    print 'isinstance(fib, Iterator): ', isinstance(fib, Iterator)

    for i in fib:
        if i > 10:
            break
        print i

if __name__ == '__main__':
    main()

在上面的代碼中,我們定義了一個(gè) Fib 類,用于生成 Fibonacci 數(shù)列。在類的實(shí)現(xiàn)中,我們定義了 __iter__ 方法,它返回對(duì)象本身,這個(gè)方法會(huì)在遍歷時(shí)被 Python 內(nèi)置的 iter() 函數(shù)調(diào)用,返回一個(gè)迭代器。類中的 next() 方法用于返回容器的下一個(gè)元素,當(dāng)使用 for 循環(huán)進(jìn)行遍歷的時(shí)候,就會(huì)使用 Python 內(nèi)置的 next() 函數(shù)調(diào)用對(duì)象的 next 方法(在 Python3 中是 __next__ 方法)對(duì)迭代器進(jìn)行遍歷。

運(yùn)行上面的代碼,可得到如下結(jié)果:

isinstance(fib, Iterator):  True
1
1
2
3
5
8

小結(jié)

  • 元組、列表、字典和字符串對(duì)象是可迭代的,但不是迭代器,不過我們可以通過 iter() 函數(shù)獲得一個(gè)迭代器對(duì)象;
  • Python 的 for 循環(huán)實(shí)質(zhì)上是先通過內(nèi)置函數(shù) iter() 獲得一個(gè)迭代器,然后再不斷調(diào)用 next() 函數(shù)實(shí)現(xiàn)的;
  • 自定義迭代器需要實(shí)現(xiàn)對(duì)象的 __iter()__next() 方法(注意:Python3 要實(shí)現(xiàn) __next__() 方法),其中,__iter()__ 方法返回迭代器對(duì)象本身,next() 方法返回容器的下一個(gè)元素,在沒有后續(xù)元素時(shí)拋出 StopIteration 異常。

參考資料

上一篇:陌生的 metaclass下一篇:單元測(cè)試