本文参考自某乎
yield
在Python中是用来暂停并返回当前操作的一个语法,其可以使用场景来说一般有三类,分别是:
- 生成器
- 上下文管理器
- 协程
- 配合 from 形成 yield from 用于消费子生成器并传递消息
其使用语法主要有四类:
-
yield
暂停当前位置 -
yield expr
,暂停并返回expr -
n = yield expr
, 暂停返回expr,并接收send
函数传过来的n
值 -
n = yidld from func()
,func
也是一个可迭代对象,此处是作用是将func
对象作为当前的迭代数据.
1. 生成器场景是使用
最常见的例子,斐波那契数列算法
def fib():
a, b = 0, 1
while True:
yield b
a, b = b, a + b
b = fib()
for i in range(10):
print(next(b), end=' ')
输出内容:
1 1 2 3 5 8 13 21 34 55
2.上下文管理器
上下文可以用来管理一些需要进行'收尾'工作的代码,例如文件打开后需要关闭,数据库连接后需要关闭等,下面是演示数据库的场景,其中使用到了contextlib.contextmanager
上下文管理模块
import sqlite3
from contextlib import contextmanager
@contextmanager
def connect():
conn = sqlite3.connect('test.db')
try:
yield conn
finally:
print('close')
conn.close()
with connect() as conn:
cur = conn.cursor()
cur.execute('create table test(name varchar(10));')
conn.commit()
3. 协程
如下有两个函数countdown
和countup
,在其需要切换的地方加上yield
,当程序运行到此处时将会中断,这是TaskScheduler
对象中的_task_queue
属性将会保存当前中断的地方,然后运行下一个函数,这样使得countdown
和countup
得以交替运行.
def countdown(n):
while n > 0:
print('T-minus', n)
yield
n -= 1
print('Blastoff!')
def countup(n):
x = 0
while x < n:
print('Counting up', x)
yield
x += 1
class TaskScheduler:
def __init__(self):
self._task_queue = []
def new_task(self, task):
'''
Admit a newly started task to the scheduler
'''
self._task_queue.append(task)
def run(self):
'''
Run until there are no more tasks
'''
while self._task_queue:
task = self._task_queue.pop(0)
try:
# Run until the next yield statement
next(task)
self._task_queue.append(task)
except StopIteration:
# Generator is no longer executing
pass
# Example use
sched = TaskScheduler()
sched.new_task(countdown(2))
sched.new_task(countup(5))
sched.run()
输出如下
T-minus 2
Counting up 0
T-minus 1
Counting up 1
Blastoff!
Counting up 2
Counting up 3
Counting up 4
- 上面的代码还可以用
asyncio
来代替,其中的asyncio.sleep(0)
也是一个async 对象.
import asyncio
async def countdown(n):
while n > 0:
print('T-minus', n)
await asyncio.sleep(0)
n -= 1
print('Blastoff!')
async def countup(n):
x = 0
while x < n:
print('Counting up', x)
await asyncio.sleep(0)
x += 1
async def main():
await asyncio.gather(countdown(2), countup(5))
asyncio.run(main())
4. 配合 from
形成 yield from
用于消费子生成器并传递消息
下面示例用来输出字典,列表的数据.
from collections.abc import Iterable
def averager(params):
if not isinstance(params, Iterable):
params = [params]
elif isinstance(params, dict):
params = params.values()
for param in params:
if isinstance(param, Iterable):
yield from averager(param)
else:
yield param
params = [1, [2, 3], (4, 5), {"p1": 6, "p7": 7}]
for param in averager(params):
print(param, end=' ')
输出内容
1 2 3 4 5 6 7
网友评论