python迭代器、生成器、yield和xrange

1,迭代器:

支持next和__iter__方法的類,

其中next需要拋出StopIteration異常或返回迭代值,

__iter__需要返回迭代器自己,

也可以實現send函數,但要保證send函數調用next。

class MyIterator(object):
    def __init__(self, step):
       self.step = step 
    def next(self):
        """Returns the next element."""
        if self.step == 0:
            raise StopIteration # 不拋出這個異常,for循環就不能捕獲而已,那麼for循環不能停止
        self.step -= 1          # 沒有return 就返回None
        return self.step
    def send(self,data):
        return self.next()
    def __iter__(self):
        return self # Returns the iterator itself

for el in MyIterator(4):
    print el

2,xrange:

xrange比迭代器高一個檔次。a = xrange(5)返回一個xrange實例對象。

xrange實例對象只支持__iter__方法,不支持next。

xrange實例對象的__iter__方法返回一個迭代器。

所以迭代器是一次性用品,而xrange可以一直返回初始狀態一樣的迭代器,可以重複使用。

for循環,首先調用對象的__iter__方法得到迭代器,然後調用迭代器的next方法。

a = xrange(5) # xrange實例對象
b = a.__iter__() # 迭代器對象
c = a.__iter__() # 迭代器對象,xrange實例對象可以多次返回相同初始狀態的迭代器
print list(b)
print list(b) # 爲空,迭代器只能用一次
print a[2],a[0] # xrange實例對象還支持切片來索引數據
print list(a)
print list(a) # 多次使用

3,yield和生成器:

yield:使用協程進行用戶態上下文切換的技術。

生成器:使用yield技術,返回支持迭代器的next、__iter__和send接口的對象。

生成器是一直執行代碼,直到遇到yeild,就返回結果值和接受輸入值,

可以有多個yeild,不一定非得是循環,

只要沒有yeild可以執行時,就拋出stopiterantion。

for只不過是有處理stopiterantion異常的代碼而已。

a.next()和a.send(None) 作用是一樣的,但第一次調用生成器時,請一定使用next()語句或是send(None)。

4,簡單的例子:

from collections import Iterable
isinstance('abc', Iterable) # str是否可迭代
isinstance(123, Iterable) # 整數是否可迭代

L = [x * x for x in range(10)] # 列表解析式
print L
g = (x * x for x in range(10)) # 返回一個生成器
print g

def fib(max):
    '斐波拉契數列用列表生成式寫不出來,但是,用函數把它打印出來卻很容易'
    n, a, b = 0, 0, 1
    while n < max:
        yield b
        a, b = b, a + b
        n = n + 1
for i in fib(20):
    print i

from itertools import groupby
def compress(data): 
    return (  (len(list(group)), name) for name, group in groupby(data) )   # 返回一個生成器
def decompress(data):
    return (car * size for size, car in data) # 返回一個生成器
list(compress('get uuuuuuuuuuuuuuuuuup'))
compressed = compress('get uuuuuuuuuuuuuuuuuup')
''.join(decompress(compressed))

5,兩種方法實現計數器:閉包和生成器:

import numpy as np
import pandas as pd

key_small = ['one','two','one','two','one']
df_small = pd.DataFrame(np.random.randn(5,3),index=['joe','steve','wes','jim','travis'],columns=['a','b','c'])
gb_small = df_small.groupby(key_small)

def f_wrapper():
    '閉包計數器'
    count = [0]
    def f(obj):
        count[0] += 1
        print '\nSTART',count[0],'\n',obj,'\nEND',count[0],'\n'
    return f
f = f_wrapper()
gb_small.agg(f)

print '-----------------------------------------------------------'
def f_counter():
    '生成器計數器'
    count = 0
    while True:
        a = yield count
        count += 1
        if count > 100:
            break
counter = f_counter() # '記住:當函數被調用時,他們返回一個生成器對象,這個對象支持迭代器接口。一定要調用,才能生成' 
def f(obj):
    count = counter.next()
    print '\nSTART',count,'\n',obj,'\nEND',count,'\n'            
gb_small.agg(f)

print '-----------------------------------------------------------'
import itertools
counter = itertools.count()
def f(obj):
    count = counter.next()
    print '\nSTART',count,'\n',obj,'\nEND',count,'\n'            
gb_small.agg(f)



(如果有什麼不對的地方,歡迎大家留言指正)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章