python中若生成列表会占用一定内存,若这个列表很大,在不使用、使用很少几个元素的情况下会浪费一些内存,因此python设计了一个叫做生成器(generator)的东西,用来动态生成列表,根据需要产生列表元素,避免内存浪费。
同时,如果需要生成一个无限大的列表,一般方法无法满足,也需要使用生成器。
不使用生成器生成列表
list = []
for i in range(1, 10000):
list.append(i)
print(list)
结果:[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11...]
生成器生成列表:列表推导式方式
# 与列表推导式不同:列表推导式是[],而生成器是()
g = (i for i in range(1, 10000))
# 获取列表元素方法一
ele_1 = g.(__next__())
# 获取列表元素方法二
ele_2 = next(g)
结果:1
2
生成器生成列表:函数方式
def func():
n = 0
while True:
n += 1
yield n
g = func()
print(next(g))
print(next(g))
结果:1
2
关于yield
普通Python函数一般结束于return、函数结束或者异常,一旦函数调用结束,函数所做工作以及保存在局部变量中的数据都会丢失,再次调用这个函数,一切都将从头创建。
yield可以看作专门给生成器使用的return,其使用方法与return大致相同,但含义有区别:
return(没有return关键字的函数可认为return None)关键字的意思就是将控制权交还调用者。而yield可翻译为产出、产生,其控制权的转移是暂时的,可以理解为保存状态+return,当再次调用时,可从保存状态中恢复数据,继续进行相关操作。
def g():
print('A')
yield 1
print('B')
yield 2
print('C')
for i in g():
print(i)
结果:A
1
B
2
C
分析:for i in g()执行g()
-->print('A')打印A
-->yield 1返回值1并保存工作状态,这里i=1
-->print(i)打印1
-->继续for i in g()执行g(),自yield 1保存的工作状态下恢复继续执行print('B'),打印B
-->yield 2返回值2并保存工作状态,这里i=2
-->print(i)打印2
-->继续for i in g()执行g(),自yield 2保存的工作状态下恢复继续执行print('C'),打印C
-->没有yield返回值,因此for操作接受不到值,停止操作
生成器经典例子:斐波那契数列
斐波那契(Fibonacci)数列是这样一个数列:斐波那契数列指的是这样一个数列 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89...。其第0项是0,第1项是第一个1,这个数列从第3项开始,每一项都等于前两项之和。
- 不用生成器:
def fab():
n, a, b = 0, 0, 1
while n < max:
print(b)
a, b = b, a + b
n += 1
print(fab(5))
- 使用生成器:仅需要把print(b)改为yield b即可
def fab(max):
n, a, b = 0, 0, 1
while n < max:
yield b
a, b = b, a + b
n = n + 1
for n in fab(5):
print(n)
结果相同:都是1 1 2 3 5