2017.6.8
学习资料:廖雪峰的官方网站
1、生成器
通过列表生成式,我们可以直接创建一个列表。但是,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。
如果可以通过一种算法,根据已经给出的数,通过循环来不断推算出后面的元素,那么我们就不必创建一个完整的list,可以节省大量的空间。
在Python中,这种一边循环一边计算的机制,称为生成器:generator。
创建一个generator
方法1
方法1:把一个列表生成式的[]改成(),就创建了一个generator:
L = [x*x for x in range(10)]
print(L)
g = (x*x for x in range(10))
for n in g:
print(n)
方法2
方法2:把函数定义中的print(b)改为yield b
例子:
如果我们要生成斐波拉契数列(Fibonacci)
1, 1, 2, 3, 5, 8, 13, 21, 34, …
这个数列的规律为:除第一个和第二个数外,任意一个数都可由前两个数相加得到:
如果我们用列表生成式的话,是写不出来的。
下面首先用函数写
def fib(max):
n =0
a,b = 0 ,1
while n <max:
print(b)
a,b=b,a+b
# t=(b,a+b)
# a=t[0]
# b=t[1]
n=n+1
return 'done'
fib(6)
注意赋值语句
a,b=b,a+b
相当于
# t=(b,a+b)
# a=t[0]
# b=t[1]
这里没有显示的写出临时变量t进行赋值
上述输出结果为
1
1
2
3
5
8
可以看出,fib函数是定义了一个推算规则,可以从前两个元素推算出后续的n个数列,这个逻辑和generator很像,如果要把这个函数改为generator,只需要把函数中的print(b)改为yield b就可以。
def fib(max):
n =0
a,b = 0 ,1
while n <max:
yield (b)
a,b=b,a+b
# t=(b,a+b)
# a=t[0]
# b=t[1]
n=n+1
return 'done'
for y in fib(4):
print(y)
输出结果为
1
1
2
3
上述的就是第2种方法来定义generator。如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator:
小结
generator的工作原理:函数是在for循环的过程中不断计算出下一个元素,并在适当的条件结束for循环。但是对于函数改成的generator来说,遇到return语句或者执行到函数体最后一行语句,就是结束generator的指令,for循环随之结束。并且对generator的调用,实际返回是一个generator的对象
>>> g = fib(6)
>>> g
<generator object fib at 0x1022ef948>
而普通函数调用直接返回结果:
>>> r = abs(-6)
>>> r
6