數(shù)學(xué)中的迭代可以指函數(shù)迭代的過程,即反復(fù)地運(yùn)用同一函數(shù)計(jì)算,前一次迭代得到的結(jié)果被用于作為下一次迭代的輸入。 即使是看上去很簡(jiǎn)單的函數(shù),在經(jīng)過迭代之后也可能產(chǎn)生復(fù)雜的行為,衍生出具有難度的問題。——引自維基百科
__iter__()和next()這兩個(gè)方法一起構(gòu)成了迭代器協(xié)議。即滿足了這個(gè)兩個(gè)方法才能稱之為迭代器。
在Python中一樣也有迭代的概念。比如循環(huán)打印出列表中的元素,這就是一個(gè)迭代的過程。在Python中,不僅可以對(duì)列表、元組、字典等進(jìn)行迭代,還可以對(duì)其他對(duì)象迭代,前提是這個(gè)對(duì)象實(shí)現(xiàn)了 __iter__方法,這個(gè)對(duì)象也稱為可迭代的對(duì)象。
具有next方法的的可迭代對(duì)象。iter方法會(huì)返回一個(gè)迭代器(__iter__返回的是迭代器本身)。在調(diào)用next方法時(shí),迭代器會(huì)返回它的下一個(gè)值,如果next方法調(diào)用后,但是又沒有值返回,就會(huì)引發(fā)StopIteration異常。
如果繼續(xù)調(diào)用,就會(huì)引發(fā)StopIteration異常
>>> iters.next()Traceback (most recent call last): File "<stdin>", line 1, in <module>StopIteration內(nèi)建函數(shù)iter()可以從可迭代的對(duì)象中獲得迭代器;list()含糊可以將迭代器顯示的以列表的形式打印
>>> test = [i for i in range(5)]>>> iters = iter(test)>>> list(iters)[0, 1, 2, 3, 4]接下來驗(yàn)證是否為迭代器
In [2]: from iters import FibsIn [3]: from collections import Iterator In [4]: from collections import Iterable # 是迭代器對(duì)象In [5]: isinstance(iter(Fibs(10)), Iterator)Out[5]: True#可迭代的對(duì)象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此時(shí)結(jié)果如下,沒有next()方法就不再是iterator了:
In [3]: from iters import Fibs#是可迭代的對(duì)象In [4]: isinstance(iter(Fibs(10)), Iterable)Out[4]: TrueIn [5]: from collections import Iterator#不是迭代器對(duì)象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).
生成器是一個(gè)函數(shù)(任何包含yield語句的函數(shù)就是生成器)這個(gè)函數(shù)的返回值是迭代器yield語句功能是為了在for循環(huán)中產(chǎn)生一系列的值;或者是使用next()一次檢索一個(gè)值每次產(chǎn)生一個(gè)值,函數(shù)就會(huì)被凍結(jié):即函數(shù)停在那點(diǎn)等待被重新喚醒。函數(shù)被重新喚醒后就從停止的那點(diǎn)開始執(zhí)行。定義生成器的兩種方式: - yield聲明 - 生成器表達(dá)式
生成器表達(dá)式返回的是生成器;生成器定義的方法類似于列表推導(dǎo)式,但是生成器用的是圓括號(hào);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]生成器表達(dá)式也可以在當(dāng)前的圓括號(hào)內(nèi)直接使用。比如在函數(shù)調(diào)用中就不需要增加另外一個(gè)圓括號(hào)了。 如果需要生成大量的的值再迭代計(jì)算,最好不要使用列表推導(dǎo)式,而是使用生成器推導(dǎo)式直接迭代。因?yàn)榱斜硗茖?dǎo)式會(huì)實(shí)例化一個(gè)列表,從而喪失迭代的優(yōu)勢(shì)。
In [50]: sum(i for i in range(10)) Out[50]: 45通過這個(gè)例子可以看出,在大量數(shù)據(jù)迭代的情況下,生成器表達(dá)式比列表推導(dǎo)式的性能好。因?yàn)榱斜硗茖?dǎo)式實(shí)實(shí)在在的生成了一個(gè)列表,在這里個(gè)例子中,先生成列表再求和,已經(jīng)是2層for循環(huán)了,自然就要慢一點(diǎn)了。
通過這個(gè)例子順便再對(duì)比一下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新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注