Python中yield语法

2020-05-11  本文已影响0人  愤愤的有痣青年

本文参考自某乎

yield在Python中是用来暂停并返回当前操作的一个语法,其可以使用场景来说一般有三类,分别是:

其使用语法主要有四类:

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. 协程

如下有两个函数countdowncountup,在其需要切换的地方加上yield,当程序运行到此处时将会中断,这是TaskScheduler对象中的_task_queue属性将会保存当前中断的地方,然后运行下一个函数,这样使得countdowncountup得以交替运行.


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
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 
上一篇下一篇

猜你喜欢

热点阅读