一、生成器定义
通过列表生成表达式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator。
1 >>> l = [x * x for x in range(10)] 2 >>> l 3 [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] 4 >>> g = (x * x for x in range(10)) 5 >>> g 6 <generator object <genexpr> at 0x1013e0780>
二、表达式生成器
创建l和g
的区别仅在于最外层的[]和(),l是一个list,而g
是一个generator。可以直接打印出l的每一个元素,打印出g的每一个元素需要使用next()函数。
1 >>> g = (x * x for x in range(10)) 2 >>> g 3 <generator object <genexpr> at 0x1013e0780> 4 >>> next(g) 5 0 6 >>> next(g) 7 1 8 >>> next(g) 9 4 10 >>> next(g) 11 9 12 >>> next(g) 13 16 14 >>> next(g) 15 25 16 >>> next(g) 17 36 18 >>> next(g) 19 49 20 >>> next(g) 21 64 22 >>> next(g) 23 81 24 >>> next(g) 25 Traceback (most recent call last): 26 File "<stdin>", line 1, in <module> 27 StopIteration
generator保存的是算法,每次调用next(g)
,就计算出g
的下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration
的错误。
1 >>> g = (x * x for x in range(10)) 2 >>> for n in g: 3 ... print(n) 4 ... 5 0 6 1 7 4 8 9 9 16 10 25 11 36 12 49 13 64 14 81
首先generator是可迭代对象,所以可以使用for in循环遍历。该遍历的本质是for in循环内部调用next()函数获取每一个元素,并且捕获StopIteration异常,结束遍历。
三、函数生成器
斐波拉契数列用列表生成式写不出来,但是,用函数把它打印出来却很容易。
1 >>> def fib(max): 2 ... n, a, b = 0, 0, 1 3 ... while n < max: 4 ... yield b 5 ... a, b = b, a + b 6 ... n += 1 7 ... raise StopIteration(‘done‘) 8 ... 9 >>> fib(6) 10 <generator object fib at 0x1013e0780> 11 >>> for i in fib(6): 12 ... print(i) 13 ... 14 1 15 1 16 2 17 3 18 5 19 8 20 >>> g = fib(6) 21 >>> while True: 22 ... try: 23 ... next(g) 24 ... except StopIteration as e: 25 ... print(e.value) 26 ... break 27 ... 28 1 29 1 30 2 31 3 32 5 33 8 34 done