Python可迭代對象、迭代器和生成器

Python可迭代對象、迭代器和生成器

python 函數 表達式 序列 count utf-8 雲棲徵文 python可迭代對象 python迭代器 python生成器python

摘要: 8.1 可迭代對象(Iterable) 大部分對象都是可迭代,只要實現了__iter__方法的對象就是可迭代的。 __iter__方法會返回迭代器(iterator)自己,例如: >>> lst = [1,2,3] >>> lst.__iter__() <listiterator objec...less

8.1 可迭代對象(Iterable)
大部分對象都是可迭代,只要實現了__iter__方法的對象就是可迭代的。
__iter__方法會返回迭代器(iterator)自己,例如:
>>> lst = [1,2,3]
>>> lst.__iter__()
<listiterator object at 0x7f97c549aa50>
Python提供一些語句和關鍵字用於訪問可迭代對象的元素,好比for循環、列表解析、邏輯操做符等。
判斷一個對象是不是可迭代對象:
>>> from collections import Iterable  # 只導入Iterable方法
>>> isinstance('abc', Iterable)     
True
>>> isinstance(1, Iterable)     
False
>>> isinstance([], Iterable)
True
這裏的isinstance()函數用於判斷對象類型,後面會講到。
可迭代對象通常都用for循環遍歷元素,也就是能用for循環的對象均可稱爲可迭代對象。
例如,遍歷列表:
>>> lst = [1, 2, 3]
>>> for i in lst:
...   print i
...
1
2
3

博客地址:http://lizhenliang.blog.51cto.com and https://yq.aliyun.com/u/lizhenliang
QQ羣:323779636(Shell/Python運維開發羣) 


8.2 迭代器(Iterator)
具備next方法的對象都是迭代器。在調用next方法時,迭代器會返回它的下一個值。若是next方法被調用,但迭代器沒有值能夠返回,就會引起一個StopIteration異常。
使用迭代器的好處:
1)若是使用列表,計算值時會一次獲取全部值,那麼就會佔用更多的內存。而迭代器則是一個接一個計算。
2)使代碼更通用、更簡單。
   8.2.1 迭代器規則
   回憶下在Python數據類型章節講解到字典迭代器方法,來舉例說明下迭代器規則:
>>> d = {'a':1, 'b':2, 'c':3}
>>> d.iteritems()
<dictionary-itemiterator object at 0x7f97c3b1bcb0>
 
# 判斷是不是迭代器
>>> from collections import Iterator
>>> isinstance(d, Iterator)
False
>>> isinstance(d.iteritems(), Iterator)
True
 
# 使用next方法。
>>> iter_items = d.iteritems()
>>> iter_items.next()
('a', 1)
>>> iter_items.next()
('c', 3)
>>> iter_items.next()
('b', 2)
因爲字典是無序的,因此顯示的是無序的,實際是按照順序獲取的下一個元素。
   8.2.2 iter()函數
   使用iter()函數轉換成迭代器:
語法:
  iter(collection) -> iterator
  iter(callable, sentinel) -> iterator
>>> lst = [1, 2, 3]
>>> isinstance(lst, Iterator)
False
>>> lst.next()  # 不是迭代器是不具有next()屬性的
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'list' object has no attribute 'next'
>>> iter_lst = iter(lst)             
>>> isinstance(iter_lst, Iterator)
True
 
>>> iter_lst.next()
1
>>> iter_lst.next()
2
>>> iter_lst.next()
3
   8.2.3 itertools模塊
itertools模塊是Python內建模塊,提供可操做迭代對象的函數。能夠生成迭代器,也能夠生成無限的序列迭代器。
有下面幾種生成無限序列的方法:
count([n]) --> n, n+1, n+2, ...
cycle(p) --> p0, p1, ... plast, p0, p1, ...
repeat(elem [,n]) --> elem, elem, elem, ... endlessly or up to n times 
也有幾個操做迭代器的方法:
   islice(seq, [start,] stop [, step]) --> elements from
chain(p, q, ...) --> p0, p1, ... plast, q0, q1, ...
groupby(iterable[, keyfunc]) --> sub-iterators grouped by value of keyfunc(v) 
imap(fun, p, q, ...) --> fun(p0, q0), fun(p1, q1), ...
ifilter(pred, seq) --> elements of seq where pred(elem) is True
 1)count生成序列迭代器
>>> from itertools import *  # 導入全部方法
      # 用法 count(start=0, step=1) --> count object
>>> counter = count()    
>>> counter.next()
0
>>> counter.next()
1
>>> counter.next()
2
...... 
可使用start參數設置開始值,step設置步長。
    2)cycle用可迭代對象生成迭代器
      # 用法 cycle(iterable) --> cycle object
>>> i = cycle(['a', 'b', 'c'])  
>>> i.next()
'a'
>>> i.next()
'b'
>>> i.next()
'c'
   3)repeat用對象生成迭代器
# 用法 repeat(object [,times]) -> create an iterator which returns the object,就是任意對象
>>> i = repeat(1)
>>> i.next()
1
>>> i.next()
1
>>> i.next()
1
......
可以使用無限次。
 
也能夠指定次數:
     >>> i = repeat(1, 2)
>>> i.next()
1
>>> i.next()
1
>>> i.next()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
   4)islice用可迭代對象並設置結束位置
      # 用法 islice(iterable, [start,] stop [, step]) --> islice object
>>> i = islice([1,2,3],2)   
>>> i.next()             
1
>>> i.next()
2
>>> i.next()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
正常的話也能夠獲取的3。
   5)chain用多個可迭代對象生成迭代器
# 用法 chain(*iterables) --> chain object
>>> i = chain('a','b','c')
>>> i.next()
'a'
>>> i.next()
'b'
>>> i.next()
'c'
   6)groupby將可迭代對象中重複的元素挑出來放到一個迭代器中
# 用法 groupby(iterable[, keyfunc]) -> create an iterator which returns
>>> for key,group in groupby('abcddCca'):
...   print key,list(group)               
...
a ['a']
b ['b']
c ['c']
d ['d', 'd']
C ['C']
c ['c']
a ['a']
groupby方法是區分大小寫的,若是想把大小寫的都放到一個迭代器中,能夠定義函數處理下:
>>> for key,group in groupby('abcddCca', lambda c: c.upper()):
...   print key, list(group)
...
A ['a']
B ['b']
C ['c']
D ['d', 'd']
C ['C', 'c']
A ['a']
   7)imap用函數處理多個可迭代對象
# 用法 imap(func, *iterables) --> imap object
>>> a = imap(lambda x, y: x * y,[1,2,3],[4,5,6])   
>>> a.next()
4
>>> a.next()
10
>>> a.next()
18
   8)ifilter過濾序列
# 用法 ifilter(function or None, sequence) --> ifilter object
>>> i = ifilter(lambda x: x%2==0,[1,2,3,4,5])
>>> for i in i:
...   print i
...
2
4
當使用for語句遍歷迭代器時,步驟大體這樣的,先調用迭代器對象的__iter__方法獲取迭代器對象,再調用對象的__next__()方法獲取下一個元素。最後引起StopIteration異常結束循環。
8.3 生成器(Generator)
什麼是生成器?
1)任何包含yield語句的函數都稱爲生成器。
2)生成器都是一個迭代器,但迭代器不必定是生成器。
8.3.1 生成器函數
在函數定義中使用yield語句就建立了一個生成器函數,而不是普通的函數。
當調用生成器函數時,每次執行到yield語句,生成器的狀態將被凍結起來,並將結果返回__next__調用者。凍結意思是局部的狀態都會被保存起來,包括局部變量綁定、指令指針。確保下一次調用時能從上一次的狀態繼續。
以生成斐波那契數列舉例說明yield使用:
斐波那契(Fibonacci)數列是一個簡單的遞歸數列,任意一個數均可以由前兩個數相加獲得。
#!/usr/bin/python
# -*- coding: utf-8 -*-
def fab(max):
    n, a, b = 0, 0, 1
    while n < max:
        print b
        a, b = b, a + b
        n += 1
fab(5)
 
# python test.py
1
1
2
3
5
使用yied語句,只須要把print b改爲yield b便可:
#!/usr/bin/python
# -*- coding: utf-8 -*-
def fab(max):
    n, a, b = 0, 0, 1
    while n < max:
        yield b
        # print b
        a, b = b, a + b
        n += 1
print fab(5)
 
# python test.py
<generator object fab at 0x7f2369495820>
可見,調用fab函數不會執行fab函數,而是直接返回了一個生成器對象,上面說過生成器就是一個迭代器。那麼就能夠經過next方法來返回它下一個值。
>>> import test
>>> f = test.fab(5)   
>>> f.next()       
1
>>> f.next()                               
1
>>> f.next()
2
>>> f.next()
3
>>> f.next()
5
每次fab函數的next方法,就會執行fab函數,執行到yield b時,fab函數返回一個值,下一次執行next方法時,代碼從yield b的嚇一跳語句繼續執行,直到再遇到yield。
8.3.2 生成器表達式
在第四章 Python運算符和流程控制章節講過,簡化for和if語句,使用小括號()返回一個生成器,中括號[]生成一個列表。
回顧下:
# 生成器表達式
>>> result = (x for x in range(5))
>>> result
<generator object <genexpr> at 0x030A4FD0>
>>> type(result)
<type 'generator'>
 
# 列表解析表達式
>>> result = [ x for x in range(5)]
>>> type(result)
<type 'list'>
>>> result
[0, 1, 2, 3, 4]
第一個就是生成器表達式,返回的是一個生成器,就可使用next方法,來獲取下一個元素:
>>> result.next()
0
>>> result.next()
1
>>> result.next()
2
......
相關文章
相關標籤/搜索