Python技术迷

简述 yield 和 yield from 关键字

在 Python 里, yield 和 yield from 这两个关键字经常会让初学者有点懵,其实理解了生成器的本质,它们用起来就特别自然。下面我就用比较口语化的方式,结合一些代码,来聊一聊这两个东西到底是干啥的。

yield 的基本作用

yield 最大的特点是能让一个函数“暂停”。普通的函数执行完就结束了,但带有 yield 的函数会变成 生成器 ,每次执行到 yield 的时候,就把一个值返回出去,同时把函数的执行状态保存住,下次再调用的时候会从上次停下来的地方继续往下跑。 举个例子:
def simple_generator():
    print("start")
    yield 1
    print("continue")
    yield 2
    print("end")

gen = simple_generator()

print(next(gen))  # 输出 start \n 1
print(next(gen))  # 输出 continue \n 2
print(next(gen))  # 抛 StopIteration
可以看到,每次调用 next 都会“推进”生成器到下一个 yield 。这比普通函数返回一个列表要省内存,尤其是处理大数据的时候特别好用。

yield from 的作用

如果说 yield 是手动一步步返回,那 yield from 就是“代理”,它会把生成器里面的 yield 全部自动转发出来。常见的场景是你有一个函数里需要从另一个生成器里拿值,这时候如果一个个写 for 去 yield 太麻烦了,直接用 yield from 就行。 先看没有 yield from 的写法:
def sub_generator():
    yield 1
    yield 2

def main_generator():
    for value in sub_generator():
        yield value
    yield 3

print(list(main_generator()))  # [1, 2, 3]
换成 yield from :
def main_generator():
    yield from sub_generator()
    yield 3

print(list(main_generator()))  # [1, 2, 3]
是不是一下子清爽很多?它还能把异常、返回值都帮你处理转发掉。

一个实际点的例子

比如你想做一个文件逐行读取的工具,如果直接 readlines() ,大文件会直接爆内存,用 yield 就可以一行一行返回:
def read_file(path):
    with open(path, "r") as f:
        for line in f:
            yield line.strip()

for line in read_file("data.txt"):
    print(line)
如果你又想在读取的时候加个转换,比如把内容都转成大写,还可以用 yield from 来组合:
def upper_lines(path):
    yield from (line.upper() for line in read_file(path))

for line in upper_lines("data.txt"):
    print(line)
这样两个生成器就像乐高一样拼起来,逻辑还很清楚。 总结一下: yield 是把函数变成生成器,可以暂停和恢复; yield from 是简化代码、代理子生成器输出的利器。一个负责“产出”,一个负责“转发”。等你习惯之后,会发现这两个东西特别适合写那种“按需生产”的逻辑。 -END -
我为大家打造了一份RPA教程, 完全免费: songshuhezi.com/rpa.html 🔥 虎哥私藏精品 🔥 虎哥作为一名老码农,整理了全网最全 《python高级架构师资料合集》 ,总量高达 650GB , 点击下方公众号回复关键字 python 全部 免费领