迭代器和生成器

 

一、手动访问迭代器中的元素

  要手动访问可迭代对象中的元素,可以使用next()函数。

with open('/etc/passwd') as f:
    try:
        while True:
            line = next(f)
            print(line, end='')
    except StopIteration:
        pass

with open('/etc/passwd') as f:
    while True:
        line = next(f,None)
        if line is None:
            break
        print(line, end='')

 

二、委托迭代

  Python的迭代协议要求__iter__()返回一个特殊的迭代器对象,由该对象实现的__next__()方法来完成实际的迭代。

  如果要做的只是迭代另一个容器中的内容,我们不必担心底层细节是如何工作的,所要做的就是转发迭代请求。

class Node:
    def __init__(self,value):
        self._value = value
        self._children = []
    
    def __repr__(self):
        return 'Node({!r})'.format(self._value)
    
    def add_children(self,node):
        self._children.append(node)
    
    def __iter__(self):
        return iter(self._children)

  __iter__()方法只是简单地将迭代请求转发给对象内部持有的_children属性上。

 

四、实现迭代协议

  实现一个迭代器能够以深度优先的模式遍历树的节点

class Node:
    def __init__(self,value):
        self._value = value
        self._children = []

    def __repr__(self):
        return 'Node({!r})'.format(self._value)

    def add_children(self,node):
        self._children.append(node)

    def __iter__(self):
        return iter(self._children)

    def depch_first(self):
        yield self
        for c in self:
            for k in  c.depch_first():
                yield k

root = Node(0)
child1 = Node(1)
child2 = Node(2)
root.add_children(child1)
root.add_children(child2)
child1.add_children(Node(3))
child1.add_children(Node(4))
child2.add_children(Node(5))

for ch in root.depch_first():
    print(ch)

# Node(0) Node(1) Node(3) Node(4) Node(2) Node(5)

 

五、定义带有额外状态的生成器函数

  如果想让生成器将状态暴露给用户,别忘了可以轻易地将其实现为一个类,然后把生成器函数的代码放到__iter__()方法中即可。

from collections import deque

class Linehistory:
    def __init__(self,lines,histlen=3):
        self.lines = lines
        self.history = deque(maxlen=histlen)
    
    def __iter__(self):
        for lineno,line in enumerate(self.lines,1):
            self.history.append((lineno,line))
            yield line
    
    def clean(self):
        self.history.clear()

with open('somefile.txt') as f:
    lines = Linehistory(f)
    for line in lines:
        if 'python' in line:
            for lineno, hline in lines.history:
                print('{}:{}'.format(lineno, hline),end='')

  使用这个类,可以将其看做是一个普通的生成器函数,但是,由于它会创建一个类实例,所以可以访问内部属性。

 

十五、合并多个有序序列、再对整个有序序列进行迭代

  heapq.merge() 要求所有的输入序列都是有序的。只是简单地检查每个输入序列中的第一个元素,将最小的那个发送出去。不断重复步骤直至耗尽。

  >>> import heapq

  >>> a = [1, 4, 7, 10]

  >>> b = [2, 5, 6, 11]

  >>> for c in heapq.merge(a,b):

  ...   print(c)      # 1 2 4 5 6 7 19 11

  文件读取写入例子:

import heapq

with open('sorted_file_1','rt') as file1,\
    open('sorted_file_2','rt') as file2,\
    open('merged_file','wt') as outf:
    
    for line in heapq.merge(file1,file2):
        outf.write(line)

 

十六、用迭代器取代while循环

  涉及I/O处理的程序中

CHUNKSIZE = 8192

def reader(s):
    while True:
        data = s.recv(CHUNKSIZE)
        if data == b''
            break
        process_data(data)

  利用iter()来替换:

def reader(s):
    for chunk in iter(lambda :s.recv(CHUNKSIZE), b''):
        process_data(data)

  iter()会创建一个迭代器,然后重复调用用户提供的可调用对象,直到它返回哨兵值为止。   

 

posted @ 2019-09-11 18:21  5_FireFly  阅读(240)  评论(0编辑  收藏  举报
web
counter