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