python 中 yield 的使用方法一直让我头疼,头疼的原因无非以下几点:
- 不明白 yield是什么
- 理不清它到底要怎么使用
- 不清楚在什么情况下使用yield
接下来,我主要从以上几点依次来说明
-
yield是什么?
yield 是Python 中的一个关键字,yield 表面上有产生、生成的意思。
如果你对yield一点概念都没有的话,你可以把yield “当成” return 理解,
我们都知道,return 函数的结束时调用的,那么yield也是一样,当函数体内执行到yield这条语句后,程序将会发生中断,不在执行yield下面的语句。
执行func函数后,控制台并没有打印输出 hello world ,这也是和return的区别。程序中断了,我们该怎么去执行它呢? 你要记得,函数中出现yield,那么这个函数就变成了一个迭代器,如何执行迭代器呢?使用next()方法可以执行
def func():
print('hello world!')
x = yield 1
print(x)
y = func()
print(next(y))
输出:
# hello world
# 1
#
执行结果分析:
· 程序开始执行以后,因为func函数中有yield关键字,所以func函数并不会真的执行,而是先得到一个生成器y(相当于一个对象)
· 直接调用 next(y),func函数才正式开始执行,先执行print(“hello world”)语句,然后执行 yield 1,这里和 return 关键字表达的意思一样,返回一个值 1,此时并没有执行 x 的赋值!
当我再次调用 next(y)的时候,会发现控制台会打印输出None,并不是我们想象的那样,x 的值为1
我们第一次调用 next(y)表示的是启动这个生成器,执行到 yield语句时发生了程序中断。下一次调用next(y)时,从上一次中断的地方继续执行下去
-
yield怎么使用?
上述说明后,我们可以大致了解到yield是什么。接下来,将说说yield两个方面的使用。
· 生成器
def gen(x):
while x > 0:
yield x
x = x - 1
for i in gen(10):
print(i)
当然也可以使用 next() 来产出值:
c = gen(3)
print(type(c)) # <class 'generator'>
g = gen(2)
print(next(g)) # 2
print(next(g)) # 1
print(next(g)) # 由于生成器中没有值了,再次取 报错
我这里描述生成器不太具体,可以参考这个网站。
· 从生成器 ---->>>>> 协程
我们通常比较常用的是多线程或者多进程,但是协程我们一般比较少用。
*大概是因为大多初学者用不明白吧哈哈哈 *
“协程就不仅仅是产出值了,而是能消费发送给它的值。”
以上这句是协程的关键句,看到这句话,是不是跟我一样不觉明厉呢~
我们接下去看
在第一个代码里,就算我们执行了两次 next(y),发现 x 的值为None,也就是yield 1 并不是对 x 进行赋值的,那么我们该如何对x 进行赋值呢?
这里我们需要使用 .send()方法,让我们瞧一瞧代码
def search_string(s):
print("寻找字符串 {}".format(s))
while True:
x = yield
if s in x:
print('{} : 成功找到~ '.format(x))
# 还是一个生成器
g = search_string('python')
print(g) # <generator object search_string at 0x0000011048B931B0>
# 激活协程!只能用一次,也可以用g.send(None)来代替next(g)
next(g) # 寻找字符串 python
# 使用.send(...)发送数据,发送的数据会成为生成器函数中yield表达式值,即变量x的值
g.send('python is beautiful')
# python is beautiful : 成功找到~
# 关闭
g.close()
代码说完啦,需要注意以下几点:
· 生成器用于生成供迭代的数据
· 协程是数据的消费者
· 协程与迭代无关
· 虽然在协程值会使用yield产出值,但这与迭代无关
-
什么情况下使用yield 呢?
以上说了那么多,我们都可以用简单的一个列表解决了呀。为什么还要这么费劲地使用yield呢?
“存在即是合理滴”
当我们的数据量很大的时候,更有经验的开发者会指出,函数在运行中占用的内存会随着列表的长度的增大而增大,如果要控制内存占用,最好不要用 List来保存中间结果,而是通过 iterable 对象来迭代。这样,我们的yield就派上用场啦~总结:yield 使用对初学者确实不太友好,但是我们多调用几次、多查查资料,相信大家都可以学会yield的使用方法!