数学中的迭代可以指函数迭代的过程,即反复地运用同一函数计算,前一次迭代得到的结果被用于作为下一次迭代的输入。 即使是看上去很简单的函数,在经过迭代之后也可能产生复杂的行为,衍生出具有难度的问题。——引自维基百科
__iter__()和next()这两个方法一起构成了迭代器协议。即满足了这个两个方法才能称之为迭代器。
在Python中一样也有迭代的概念。比如循环打印出列表中的元素,这就是一个迭代的过程。在Python中,不仅可以对列表、元组、字典等进行迭代,还可以对其他对象迭代,前提是这个对象实现了 __iter__方法,这个对象也称为可迭代的对象。
具有next方法的的可迭代对象。iter方法会返回一个迭代器(__iter__返回的是迭代器本身)。在调用next方法时,迭代器会返回它的下一个值,如果next方法调用后,但是又没有值返回,就会引发StopIteration异常。
如果继续调用,就会引发StopIteration异常
>>> iters.next()Traceback (most recent call last): File "<stdin>", line 1, in <module>StopIteration内建函数iter()可以从可迭代的对象中获得迭代器;list()含糊可以将迭代器显示的以列表的形式打印
>>> test = [i for i in range(5)]>>> iters = iter(test)>>> list(iters)[0, 1, 2, 3, 4]接下来验证是否为迭代器
In [2]: from iters import FibsIn [3]: from collections import Iterator In [4]: from collections import Iterable # 是迭代器对象In [5]: isinstance(iter(Fibs(10)), Iterator)Out[5]: True#可迭代的对象In [6]: isinstance(iter(Fibs(10)), Iterable)Out[6]: True注释掉next()方法
#!/usr/bin/pythonclass Fibs: value = 0 def __init__(self,ranges): self.ranges = ranges #def next(self): #self.value += 1 #if self.value == self.ranges: raise StopIteration #return self.value def __iter__(self): return self此时结果如下,没有next()方法就不再是iterator了:
In [3]: from iters import Fibs#是可迭代的对象In [4]: isinstance(iter(Fibs(10)), Iterable)Out[4]: TrueIn [5]: from collections import Iterator#不是迭代器对象In [6]: isinstance(iter(Fibs(10)), Iterator)Out[6]: FalseA function which returns an iterator. It looks like a normal function except that it contains yield statements for producing a series a values usable in a for-loop or that can be retrieved one at a time with the next() function. Each yield temporarily suspends processing, remembering the location execution state (including local variables and pending try-statements). When the generator resumes, it picks-up where it left-off (in contrast to functions which start fresh on every invocation).
生成器是一个函数(任何包含yield语句的函数就是生成器)这个函数的返回值是迭代器yield语句功能是为了在for循环中产生一系列的值;或者是使用next()一次检索一个值每次产生一个值,函数就会被冻结:即函数停在那点等待被重新唤醒。函数被重新唤醒后就从停止的那点开始执行。定义生成器的两种方式: - yield声明 - 生成器表达式
生成器表达式返回的是生成器;生成器定义的方法类似于列表推导式,但是生成器用的是圆括号;list()方法可以把生成器以列表的形式显示出来;
In [53]: g = (i for i in range(10))In [54]: gOut[54]: <generator object <genexpr> at 0x20c5eb0>In [55]: list(g)Out[55]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]生成器表达式也可以在当前的圆括号内直接使用。比如在函数调用中就不需要增加另外一个圆括号了。 如果需要生成大量的的值再迭代计算,最好不要使用列表推导式,而是使用生成器推导式直接迭代。因为列表推导式会实例化一个列表,从而丧失迭代的优势。
In [50]: sum(i for i in range(10)) Out[50]: 45通过这个例子可以看出,在大量数据迭代的情况下,生成器表达式比列表推导式的性能好。因为列表推导式实实在在的生成了一个列表,在这里个例子中,先生成列表再求和,已经是2层for循环了,自然就要慢一点了。
通过这个例子顺便再对比一下xrange()和range()的性能吧
In [62]: time sum(i for i in xrange(10000000)) CPU times: user 0.50 s, sys: 0.00 s, total: 0.50 sWall time: 0.50 sOut[62]: 49999995000000In [63]: time sum(i for i in range(10000000)) CPU times: user 0.59 s, sys: 0.60 s, total: 1.19 sWall time: 1.19 sOut[63]: 49999995000000新闻热点
疑难解答