可迭代、迭代器、生成器解析

歸納

  • 容器是一系列元素的集合,str、tuple、list、set、dict、file、sockets類型的對象均可以看做是容器。
  • 一個對象實現了__iter__()方法,就是可迭代對象。容器都都是可迭代對象,他們能夠在for…in…,while…語句中被迭代。
  • 一個對象同時實現了__iter__()方法與__next__()方法,或者說一個可迭代對象實現了__next__()方法,就是迭代器。迭代器持有一個內部狀態的字段,用於記錄下次迭代返回值,迭代器不會一次性把全部元素加載到內存,而是須要的時候才生成返回結果。
  • 生成器是一種特殊的迭代器,它的返回值不是經過return而是用yield。

可迭代對象

一個對象實現了__iter__()方法,就是可迭代對象。咱們經過兩種方法判斷str、tuple、range、list、set、dict類型的容器是否爲可迭代對象。一種方法是經過dir()函數查看目標對象是否具備__iter__()方法;另外一種方法是從collections模塊中導入Iterable屬性,利用isinstance()函數判斷目標對象是否爲Iterable類型,若是是的話,該目標對象即爲可迭代對象。python

s = 'my name is david'              #str類型
t = (1,2,3,'a','5')                 #tuple類型
r = range(10)                       #range類型
l = [1,2,3,4,5]                     #list類型
st = {'a','b','c',4,5}               #set類型
d = {'a':1,'b':2,'c':3,'d':4}       #dict類型

from collections import Iterable      #使用Iterable屬性判斷目標對象是否爲可迭代對象
print(isinstance(s,Iterable))
print(isinstance(t,Iterable))
print(isinstance(r,Iterable))
print(isinstance(l,Iterable))
print(isinstance(st,Iterable))
print(isinstance(d,Iterable))

迭代器

一個對象同時實現了__iter__()方法與__next__()方法,就是迭代器。爲了更直觀地感覺迭代器,咱們自定義一個斐波那契數列類Fib,將該類實例化以後能夠生成迭代器。socket

class Fib:
    def __init__(self):
        self.prev = 0
        self.curr = 1
    def __iter__(self):   #一個對象實現__iter__()方法,就是可迭代對象。
        return self 
    def __next__(self):    #一個可迭代對象實現__next__()方法,就是迭代器。
        value = self.curr
        self.curr += self.prev
        self.prev = value
        return value

f = Fib()
from collections import Iterable, Iterator
print(isinstance(f,Iterable))    #f既是可迭代對象
print(isinstance(f,Iterator))    #f也是迭代器

在這裏,咱們經過創建一個Fib類,而後實例化爲一個f對象的形式自定義一個迭代器。能夠說自定義迭代器的方式是比較笨拙的,後面咱們會介紹生成器,與迭代器相比,自定義生成器是比較簡潔、優雅的。函數

迭代器不會一次性將全部的元素都加載到內存,等到使用next()調用的時候纔給它生成值返回,沒調用的時候就處於休眠狀態等待下一次調用。itertools模塊中的函數返回的都是迭代器對象。工具

from collections import Iterator

from itertools import count
counter = count(start=13)
print(isinstance(counter,Iterator))

from itertools import cycle
colors = cycle(['red','yellow','blue'])
print(isinstance(colors,Iterator))

from itertools import islice
iterslice = islice(counter,2,12)
print(isinstance(iterslice,Iterator))

使用python內置函數iter()能夠將可迭代對象變成迭代器。code

from collections import Iterator
s = 'my name is david'              #str類型
t = (1,2,3,'a','5')                 #tuple類型
r = range(10)                       #range類型
l = [1,2,3,4,5]                     #list類型
st = {'a','b','c',4,5}               #set類型
d = {'a':1,'b':2,'c':3,'d':4}       #dict類型
si = iter(s)
print(isinstance(si,Iterator))
ti = iter(t)
print(isinstance(ti,Iterator))
ri = iter(r)
print(isinstance(ri,Iterator))
li = iter(l)
print(isinstance(li,Iterator))
sti = iter(st)
print(isinstance(sti,Iterator))
di = iter(d)
print(isinstance(di,Iterator))

Python 3中關於iter(object[, sentinel])方法有兩個參數。 使用iter(object)這種形式比較常見。 iter(object, sentinel)這種形式通常較少使用,Python的文檔說明貌似也不容易理解。對象

生成器

生成器(generator)是一種特殊的迭代器,與迭代器相比,生成器更爲優雅。它不須要再像上面的類同樣寫__iter__()和__next__()方法,只須要一個yiled關鍵字,像定義函數同樣自定義生成器。咱們建立了一個生成器後,基本上永遠不會調用next()方法,而是經過for循環來迭代它。 與自定義迭代器相比,下面這種使用生成器來建立斐波那契數列的方式是否是更優雅?內存

def fib():
    prev, curr = 0, 1
    while True:
        yield curr
        prev, curr = curr, curr + prev
f = fib()           #建立迭代器
from itertools import islice   #導入迭代器切片工具
list(islice(f,0,10))

此外,咱們還可使用生成器表達式來構造生成器。與列表生成式相似,只須要把一個列表生成式的[]改爲(),就能夠建立一個生成器。文檔

>>> l = [x*x for x in range(10)]
>>> l
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> g = (x*x for x in range(10))
>>> g
<generator object <genexpr> at 0x0000026428DEC308>
相關文章
相關標籤/搜索