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

    ***  迭代器(Iterator)

      ---- 当要返回一个序列或者在循环中执行的函数时,就应该考虑生成器,这些元素将被传递到另一个函数中进行后续处理时,一次返回一个元素能够提高整体性能。  

      ---- 迭代器只不过是一个实现迭代协议的容器对象,它基于两个方法:1)next (python 3 是__next__):返回容器的下一个项目; 2)__iter__ :返回迭代器本身。前者返回迭代过程的下一个集合元素而后者返回一个迭代器对象(如果一个对象没有__iter__方法但定义了__getitem__方法,那么这个对象仍然是可迭代的)。

      ---- python 用for或列表推导式(list comprehension)能够自动为你调用next和iter这两个方法。在for循环中,Python将自动调用工厂函数iter()获得迭代器,自动调用next()获取元素,还完成了检查StopIteration异常的工作。若需手动调用它们,用Python的内建函数iter以及 next。 若c是一个可迭代对象,那么你可以使用iter(c)来访问;如果a是一个迭代器对象,那么请使用next(a)

      ---- 迭代器的实现

    ###1
    class count_iterator(object):
        n = 0
        def __iter__(self):
            return self
     
        def next(self):
            y = self.n
            self.n += 1
            return y
    
    counter = count_iterator()
    #next(counter)
    
    ###2
    class SimpleList(object):
        def __init__(self, *items):
            self.items = items
     
        def __getitem__(self, i):
            return self.items[i]
    
    a = SimpleList(1, 2, 3)
    it = iter(a)#当Python的内建函数iter将会返回一个对应此对象的迭代器类型,并使用__getitem__方法遍历list的所有元素。如果 StopIteration或IndexError异常被抛出,则迭代停止。
    #next(it)
    View Code

      --- iter(callable, flagValue)  iter 函数一个鲜为人知的特性是它接受一个可选的 callable 对象和一个标记(结尾)值作为输入参数。 当以这种方式使用的时候,它会创建一个迭代器, 这个迭代器会不断调用 callable 对象直到返回值和标记值相等为止。

    *** 生成器(Generator)

      ---- yield只适用于函数.当生成器被调用的时候,它会返回一个值给调用者。在生成器内部使用yield来完成这个动作。为了记住yield到底干了什么,最简单的方法是把它当作专门给生成器函数用的特殊的return。调用next()时,生成器函数不断的执行语句,直至遇到yield为止,此时生成器函数的"状态"会被冻结,所有的变量的值会被保留下来,下一行要执行的代码的位置也会被记录,直到再次调用next()继续执行yield之后的语句。next()不能无限执行,当迭代结束时,会抛出StopIteration异常。迭代未结束时,如果你想结束生成器,可以使用close()方法。

      ---- 它可以使用空的return语句结束

      ---- 生成器函数可以带参数

      ---- 如果我需要在生成器的迭代过程中接入另一个生成器的迭代(p3.3后实现委托生成器yield from)

    def frange(start, stop, increment):
        x = start
        while x < stop:
            yield x
            x += increment
    
    #生成器只能用于迭代操作,一旦生成器函数返回退出,迭代终止。
    for n in frange(0, 4, 0.5):
        print(n)
    View Code

      ---- 带有外部状态的生成器函数实现

    #关于生成器,很容易掉进函数无所不能的陷阱。 如果生成器函数需要跟你的程序其他部分打交道的话(比如暴露属性值,允许通过方法调用来控制等等), 可能会导致你的代码异常的复杂。 如果是这种情况的话,可以考虑使用如下定义类的方式。 在 __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 clear(self):
            self.history.clear()
    View Code

      ---- 迭代器代替while的无限循环。

  • 相关阅读:
    elasticsearch 事务日志 sync 都干了些什么?
    elasticsearch 事务日志是个啥东西?
    elasticsearch 分片恢复经历了哪些步骤?
    定向爬取网页内容
    文件查询之三:文件和目录的批量操作
    文件查询之二:文件属性查询
    文件查询之一:文件名和文件后缀查询
    记一次SQL联合查询注入工具的编写
    线程间使用socket通信的计算器
    简单的远程加解密文件
  • 原文地址:https://www.cnblogs.com/holens/p/5641662.html
Copyright © 2011-2022 走看看