372-Python生成器
生成器是什么
根据程序设计者制定的规则循环生成数据,当条件不成立时则生成数据结束
作用
数据不是一次性全部生成出来,而是使用一个,再生成一个,可以节约大量的内存,降低程序运行消耗时间。
创建生成器的方式
① 推导式 生成器
② yield 关键字生成器
推导式生成器
与列表推导式类似,只不过生成器推导式使用小括号。
109-推导式(数据容器)
# 创建生成器
my_generator = (i * 2 for i in range(5))
print(my_generator)
(i * 2 for i in range(5))
是生成器
[i * 2 for i in range(5)]
是直接生成现成的列表
(i * 2 for i in range(5))
本质是一个对象,其中没有02468这些数据,只有数据生成的规则
如果打印my_generator
,那么打印的只是这个对象的内存地址
# next 获取生成器下一个值
value = next(my_generator)
print(value)
- 使用next()函数获取生成器的元素:
生成器中有一个关键的函数:next(),每调用一次就会根据规则创建一个元素,然后向后移动,再次调用next()函数就会再生成一个元素
# 遍历生成器
for value in my_generator:
print(value)
- for 循环遍历生成器中的每一个值
yield生成器
yield生成器是啥
重点理解yield生成器的执行流程
yield生成器结构:
- 定义一个函数
- 函数内部存在一个yield关键字
yield 关键字生成器的特征:在def函数中具有yield关键字
当函数和yield组合在一起就叫做生成器,这个函数就不是函数了,就转变成了对象
代码演示:
用next函数获取生成器的元素
def generator(n):
for i in range(n):
print('开始生成数据')
yield i # 暂时可以把yield当成return理解,每次遇到yield,生成器就相当于执行一次(生成循环执行到yield后就暂停,后面在调用就从这里继续执行,意思就是'完成一次数据生成'这句话会在第二次生成的时候打印)
print('完成一次数据生成')
# 使用时,由于生成器需要传递参数,所以通常将其赋予给某个变量
g = generator(5)
# 如果print(generator(5)),输出的是对象的内存地址
print(next(g))
print(next(g))
print(next(g))
print(next(g))
print(next(g)) -----> 正常
print(next(g)) -----> 报错
Traceback (most recent call last):
File "/Users/cndws/PycharmProjects/pythonProject/demo.py", line 14, in <module>
print(next(g))
StopIteration(到达边界)
但是这里执行第六次next()会把'完成一次数据生成'这句打印出来
用for循环遍历生成器的元素
for循环的好处:可以避免上面出现的到达边界的错误
def generator(n):
for i in range(n):
print('开始生成...')
yield i
print('完成一次...')
g = generator(5)
for i in g:
print(i)
使用while循环+try...except语句获取生成器元素
这样同样可以避免到达边界的错误
def generator(n):
for i in range(n):
print('开始生成...')
yield i
print('完成一次...')
g = generator(5)
while True:
try:
print(next(g))
except StopIteration:
break
yield关键字和return关键字
如果不太好理解yield
,可以先把yield
当作return
的同胞兄弟来看,他们都在函数中使用,并履行着返回某种结果的职责。
这两者的区别是:
有return
的函数直接返回所有结果,程序终止不再运行,并销毁局部变量;
def example():
x = 1
return x
example = example()
print(example)
而有yield
的函数则返回一个可迭代的 generator(生成器)对象,你可以使用for循环或者调用next()方法遍历生成器对象来提取结果。
def example():
x = 1
y = 10
while x < y:
yield x
x += 1
example = example()
print(example)
生成器的现实应用案例
斐波那契数列:数学中的一个概念,是一组有规律的数字!
1 1 2 3 5 8 13 21 34 55 ...
规律:
隐藏了一个元素 => 0
第1个元素为1
第2个元素为1,第2个元素为1,实际上是由0 + 1 = 隐藏元素 + 第一个元素
第3个元素为2 = 1 + 1,第3个元素值 = 第2个元素值 + 第1个元素值
第4个元素为3 = 2 + 1,第4个元素值 = 第3个元素值 + 第2个元素值
刚好满足:数据量比较大,而且还要经过大量的计算 => 符合生成器的使用规则
0 1 1 2 3 5 8 13 21 34 55 ...
a变量代表,斐波那契数列中前一个元素,比如a可以代表0
b变量代表,斐波那契数列中后一个元素,比如b可以代表1
a,b是相邻的两个元素
def fib(max): # 求max位斐波那契数列 => 前max位斐波那契数列的每个值
n, a, b = 0, 0, 1
while n < max:
yield b # 第一次循环,弹出一个1
# 想个办法,让第二次yield b,弹出一个1,第三次yield b,弹出一个2
# a = 0, b = 1
a, b = b, a + b
# a = 1, b = 1
n += 1
result = fib(50)
for i in result:
print(i)
使用生成器的注意事项:
① 代码执行到 yield 会暂停,然后把结果返回出去,下次启动生成器会在暂停的位置继续往下执行
② 生成器如果把数据生成完成,再次获取生成器中的下一个数据会抛出一个StopIteration 异常,表示停止迭代异常
③ while 循环内部没有处理异常操作,需要手动添加处理异常操作
④ for 循环内部自动处理了停止迭代异常,使用起来更加方便,推荐大家使用。