python中的生成器(generator)总结

1.实现generator的两种方式python

python中的generator保存的是算法,真正须要计算出值的时候才会去往下计算出值。它是一种惰性计算(lazy evaluation)。算法

要建立一个generator有两种方式。数据结构

第一种方法:把一个列表生成式的[]改为(),就建立了一个generator:函数

>>> L = [x * x for x in range(10)]
>>> L
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> g = (x * x for x in range(10))   # 注意把[]改为()后,不是生成一个tuple,而是生成一个generator
>>> g
<generator object <genexpr> at 0x1022ef630>

第二种方式:在函数中使用yield关键字,函数就变成了一个generator。性能

函数里有了yield后,执行到yield就会停住,当须要再往下算时才会再往下算。因此生成器函数即便是有无限循环也不要紧,它须要算到多少就会算多少,不须要就不往下算。lua

def fib():
a, b = 0, 1
while True:
yield a
a, b = b, a + b


f = fib()
print f, next(f), next(f), next(f)
# <generator object fib at 0x7f89769d1fa0> 0 1 1

如上例,第一次输出f,它就是一个generator,以后每次next,它就执行到yield a。spa

固然其实日常不多用到next(),咱们直接用for循环就能够遍历一个generator,其实for循环的内部实现就是不停调用next()。code

生成器能够避免没必要要的计算,带来性能上的提高;并且会节约空间,能够实现无限循环(无穷大的)的数据结构。对象

 

2.可迭代对象(Iterable)和迭代器(Iterator)的概念blog

能够直接做用于for循环的对象统称为可迭代对象:Iterable

包括集合数据类型(listtupledictsetstr等)和生成器(generator)。

可使用isinstance()判断一个对象是不是Iterable对象。

>>> from collections import Iterable
>>> isinstance([], Iterable)
True
>>> isinstance({}, Iterable)
True
>>> isinstance('abc', Iterable)
True
>>> isinstance((x for x in range(10)), Iterable)
True
>>> isinstance(100, Iterable)
False

迭代器:Iterator。

它表示的是一个数据流,Iterator对象能够被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。能够把这个数据流看作是一个有序序列,但咱们却不能提早知道序列的长度,只能不断经过next()函数实现按需计算下一个数据,因此Iterator的计算是惰性的,只有在须要返回下一个数据时它才会计算。Iterator甚至能够表示一个无限大的数据流,例如全体天然数。而使用list是永远不可能存储全体天然数的。

生成器(generator)都是Iterator对象,但listdictstr虽然是Iterable,却不是Iterator

listdictstrIterable变成Iterator可使用iter()函数:

>>> isinstance(iter([]), Iterator)
True
>>> isinstance(iter('abc'), Iterator)
True

Python的for循环本质上就是经过不断调用next()函数实现的,例如:

for x in [1, 2, 3, 4, 5]:
    pass

实际上彻底等价于:

# 首先得到Iterator对象:
it = iter([1, 2, 3, 4, 5])
# 循环:
while True:
    try:
        # 得到下一个值:
        x = next(it)
    except StopIteration:
        # 遇到StopIteration就退出循环
        break

 

3.itertools模块

python的内置模块itertools提供了用于操做迭代对象的函数,很是方便实用。举一个例子:

islice(iterable, [start, ] stop [, step]):

建立一个迭代器,生成项的方式相似于切片返回值: iterable[start : stop : step],将跳过前start个项,迭代在stop所指定的位置中止,step指定用于跳过项的步幅。与切片不一样,负值不会用于任何start,stop和step,若是省略了start,迭代将从0开始,若是省略了step,步幅将采用1.

from itertools import islice


def fib():
    a, b = 0, 1
    while True:
        yield a
        a, b = b, a + b


f = fib()
print list(islice(f, 10))# [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
相关文章
相关标签/搜索