美文网首页
python协程(1):yield表达式

python协程(1):yield表达式

作者: 米那斯提力斯 | 来源:发表于2022-02-11 13:42 被阅读0次

    什么是yield关键字

    先看一段代码:

    def my_generator(n):
        for i in range(n):
            yield i
    
    f = my_generator(3)
    print(f.__next__())
    print(f.__next__())
    print(f.__next__())
    
    运行结果:
    0
    1
    2
    

    yield关键字会将一个函数变成一个生成器,生成器和普通函数不同,它不会直接执行函数代码,而需要调用__next__()(在 for 循环中会自动调用 next())才开始执行。虽然执行流程仍按函数的流程执行,但每执行到一个 yield 语句就会中断,并返回一个迭代值,下次执行时从 yield 的下一个语句继续执行。看起来就好像一个函数在正常执行的过程中被 yield 中断了数次,每次中断都会通过 yield 返回当前的迭代值。

    生成器的应用

    应用示例1

    def read_file(fpath):
        BLOCK_SIZE = 20
        with open(fpath, 'rb') as f:
            while True:
                block = f.read(BLOCK_SIZE)
                if block:
                    yield block
                else:
                    return
    
    
    f = read_file('testfile.txt')
    print(f.__next__())
    print(f.__next__())
    
    运行结果:
    b'FastAPI is a modern,'
    b' fast (high-performa'
    

    读取文件,每次读取20个字节

    应用示例2

    for i in range(1000):
        print(i)
    

    会导致生成一个 1000 个元素的 List

    for i in xrange(1000):
        print(i)
    

    不会生成一个 1000 个元素的 List,而是在每次迭代中返回下一个数值,内存空间占用很小。因为 xrange 不返回 List,而是返回一个 iterable 对象

    yield语句的用法总结

    yield的一般形式为:

    temp=yield 表达式(每次迭代要返回的值)

    (1)如果要返回确定的值,后面的表达式不可省略,绝大部分情况下我们也不省略,否则只能返回None;

    (2)如果使用了send(value),传递进去的那个value回取代那个表达式的值,并且会将传递进去的那个值返回给yield表达式的结果temp,所以如果想在yield后面使用传递进去的那个值,必须要有使用temp,否则无法使用;

    send()方法的使用

    def my_generator(n):
        for i in range(n):
            temp = yield i
            print(f'我是{temp}')
    
    
    g = my_generator(5)
    
    print(next(g))  # 输出0
    print(next(g))  # 输出1
    g.send(100)  # 本来输出2,但是传入新的值100,改为输出100
    print(next(g))  # 输出3
    print(next(g))  # 输出4
    
    运行结果:
    0
    我是None
    1
    我是100
    我是None
    3
    我是None
    4
    

    从上面可以看出yield语句与普通函数的return语句的区别在哪里了,主要集中在以下几点

    (1)return 不能写成“temp=return xxxx”的形式,会提示语法错误,但是yield可以写成“temp=yield xxxx”的形式;

    (2)普通函数return后面的语句都是不会再执行的,但是yield语句后面的依然会执行,但是需要注意的是,由于“延迟加载”特性,yield后面的代码并不是在第一次迭代的时候执行的,而是第二次迭代的时候才执行第一次yield后面没有执行的代码。也正是这个特性,构成了yield为什么是实现协程的最简单实现。

    (3)使用send()方法传进去的值,实际上就是yield表达式返回的值,这就是为什么前面每次输出print(temp)都打印出None,因为没有send值,所以temp为None,但是send(100)之后却打印100,因为此时temp就是100了。

    可以看到迭代器并没有输出2,那是因为g.send(100)是有返回值的,返回值内容就是2

    send(arg)方法总结:

    (1)它的主要作用是,当我需要手动更改生成器里面的某一个值并且使用它,则send发送进去一个数据,然后保存到yield语句的返回值,以提供使用

    (2)send(arg)的返回值就是那个本来应该被迭代出来的那个值。这样既可以保证我能够传入新的值,原来的值也不会弄丢

    相关文章

      网友评论

          本文标题:python协程(1):yield表达式

          本文链接:https://www.haomeiwen.com/subject/csyakrtx.html