zoukankan      html  css  js  c++  java
  • 迭代器和生成器

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

      要手动访问可迭代对象中的元素,可以使用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()会创建一个迭代器,然后重复调用用户提供的可调用对象,直到它返回哨兵值为止。   

  • 相关阅读:
    ffmpeg rtmp推流 视频转码
    java日志发展史 log4j slf4j log4j2 jul jcl 日志和各种桥接包的关系
    nginx stream 流转发,可以转发rtmp、mysql访问流,转发rtmp、jdbc请求
    java web http 转https 通过nginx代理访问
    linux 服务器磁盘挂载
    novnc 通过websockify代理 配置多点访问
    linux 文件服务 minio 安装部署配置
    AOP实现原理,手写aop
    java 泛型
    JAVA反射getGenericSuperclass()用法
  • 原文地址:https://www.cnblogs.com/5poi/p/11507905.html
Copyright © 2011-2022 走看看