【Python进阶】彻底理解Python中的yield

yield特性、使用规则与使用方法

  1. 通常的for…in…循环中,in后面是一个数组,这个数组就是一个可迭代对象,类似的还有链表,字符串,文件。它可以是mylist = [1, 2, 3],也可以是mylist = [x*x for x in range(3)]。它的缺陷是所有数据都在内存中,如果有海量数据的话将会非常耗内存。例如:
# 假如一间公司的业务是定制盒子,一个客户与公司签了一个大单,客户只给了定金:
# 于是没经验的公司一次生产了全部的盒子
box = [x for x in range(1, 10000000)]  # 生成1000000个box
# 突然客户因某事破产,不能支付后面的费用,因为是定制盒子,所以后面的盒子就造成了浪费
  1. 生成器是可以迭代的,但只可以读取它一次。因为用的时候才生成。generator = (x*x for x in range(3))就是一个生成器写法,注意这里用到了(),它就不是数组,而上面的例子是[]。
box = (x for x in range(1, 10000000))
type(box) 
# 显示<class 'generator'> generator就是生成器的意思
# 而生成器box并不会一次先把产品全生产出来,只是形成一个生成器具
  1. 生成器(generator)能够迭代的关键是它有一个next()方法,工作原理就是通过重复调用next()方法,直到捕获一个异常StopIteration, 就是后面已经没数据了,所以抛出异常;如果想避免这个异常,可以用except StopIteration捕获异常,也可以使用for来接收去迭代一个生成器。
box = (x for x in range(1, 10000000))
next(box) # 输出1
next(box) # 输出2
#===============分割线============
# 从生成器不停迭代,直到结束(不会报错)
for item in box:
	print(item)
  1. 带有 yield 的函数不再是一个普通函数,而是一个生成器generator,可用于迭代,工作原理同上。 yield 是一个类似return的关键字,迭代一次遇到yield时就返回yield后面(右边)的值。重点是:下一次迭代时,从上一次迭代遇到的yield后面的代码(下一行)开始执行。简要理解:yield就是 return 返回一个值,并且记住这个返回的位置,下次迭代就从这个位置后(下一行)开始。
def generator():
	for x in range(3):
		print('当前输出是{}'.format(x))
		yield 

a = generator()  # a是一个生成器
for i in a:
	pass
# 当前输出是0
# 当前输出是1
# 当前输出是2
  1. send()可以传递参数给yield表达式,这时传递的参数会作为yield表达式的值,而yield的参数是返回给调用者的值。——换句话说,就是send可以强行修改上一个yield表达式值。比如函数中有一个yield赋值,x = yield 5,第一次迭代到这里会返回5,x并没有被赋值。第二次迭代时,使用.send(10),那么,就是强行修改yield 5表达式的值为10,本来是5的,那么a=10,并且向后面执行,执行至下一个yield,否则抛出StopIteration异常, 表示迭代完成。
# ====================有无限个yield======================
def generator():
	while True:
		x = yield 5
		print('当前输出是{}'.format(x))


a = generation()
# =====情况一=====
b = next(a)
print(b)  # 接收yield后面的值
c = a.send(10)  # 执行x = 10 并且依旧返回值
print(c)
输出
5
当前输出是10
5
# =====情况二====
next(a)
next(a)
输出
当前输出是None # 因为x并没有被赋值



# ====================只有一个yield======================
def generator():
	x = yield 5
	print('当前输出是{}'.format(x))


a = generator()
b = next(a)
print(b)
next(a)
输出
5
当前输出是None
抛出StopIteration异常(因为后面没有可迭代的数据)
  • 第一次调用时必须先next()或send(None),否则会报错,参照第五条, 因为send()是修改上一个表达式的值,所以send()值得话会报错。可以认为,next()等同于send(None)。

总结

另外说一句,yield也是协程的一个关键语句。另外说几点:

  • 生成器用于生成供迭代的数据
  • 协程是数据的消费者
  • 协程与迭代无关
  • 虽然在协程值会使用yield产出值,但这与迭代无关

直接调用yield返回的是一个生成器对象,函数内部代码不会执行,使用next方法时,这个函数开始执行到yield为止并返回yield之后的内容,接着继续暂停执行,只有在调用next方法,程序才会从刚才暂停的地方执行下一次直到再遇到yield。

参考原文:https://blog.csdn.net/qq_36330643/article/details/78247070
参考原文:https://blog.csdn.net/weixin_42218582/article/details/90743448

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值