ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

《Python进阶》协程详解:用 send() 让 yield 从“产出数据“变为“消费数据“

《Python进阶》协程详解:用 send() 让 yield 从“产出数据“变为“消费数据“ 教程文档教育【免费下载链接】interpy-zh《Python进阶》Intermediate Python - Chinese Version项目地址https://gitcode.com/gh_mirrors/in/interpy-zh点击查看免费下载本文是《Python进阶》interpy-zh 中文译本数据结构章节中协程主题的深度指南。协程与生成器共享yield语法却扮演着截然相反的角色生成器是数据的生产者协程则是数据的消费者。读完本文你将掌握用next()启动协程、用send()向协程喂数据、用close()关闭协程的完整流程并能读懂仓库中 code/2.7/23_coroutine.py 的实战实现为后续学习异步编程打下基础。协程与生成器同源而殊途在 Python 中协程Coroutine和生成器Generator长得非常像——它们都使用yield关键字、都以函数形式编写但两者的定位有本质区别生成器是数据的生产者它通过yield源源不断地吐出值供外部消费协程是数据的消费者它通过yield接收外部喂入的值再对这些值进行加工处理。一句话概括同一个yield向外产出值时它是生成器向内接收值时它就变成了协程。第一步回顾生成器的创建与使用要理解协程先要熟悉生成器。在 book/DataStructures/generators.md 中已经系统讲解了迭代器Iterator、可迭代对象Iterable与迭代Iteration三者的关系。这里回顾最经典的斐波那契生成器写法def fib(): a, b 0, 1 while True: yield a a, b b, a b配合for循环使用for i in fib(): print(i)这样做有两个好处快值在迭代过程中实时产出不需要先构建完整序列省内存斐波那契数列的每一项都是动态生成的而不是被一次性存储到一个列表中——这正是 book/DataStructures/generators.md 强调的生成器最佳应用场景你不想同一时间将所有计算出来的大量结果集分配到内存当中。第二步把yield变成接收通道——grep 协程如果我们在生成器中把yield放在表达式位置如line (yield)并去掉yield后面的产出值函数就不再向外部产出数据而是等待外部向它发送数据——它变成了一只协程。原文档给出的 Python 版grep就是最直观的例子def grep(pattern): print(Searching for, pattern) while True: line (yield) if pattern in line: print(line)对比斐波那契生成器这里有三个关键变化对比维度生成器 fib协程 grepyield的形态yield a带产出值(yield)裸 yield作为表达式数据流向函数体向外产出值外部向函数体注入值角色数据生产者数据消费者line (yield)这行代码是整个协程的接收口外部发送进来的值会被yield表达式接住并赋值给line随后if pattern in line会对接收到的每一行文本做模式匹配命中则打印。整个while True循环让协程可以无限次地接收数据、处理数据而不是处理完一次就结束。第三步用send()向协程喂数据协程不再自带初始值而是从外部传值给它这个传值动作由生成器协议的send()方法完成。原文档给出了完整的调用序列search grep(coroutine) next(search) # output: Searching for coroutine search.send(I love you) search.send(Dont you love me?) search.send(I love coroutine instead!) # output: I love coroutine instead!逐行拆解这段代码的执行过程search grep(coroutine)调用协程函数不会立即执行函数体只是创建一个协程对象next(search)启动协程函数体开始执行先打印Searching for coroutine随后执行到line (yield)挂起等待search.send(I love you)将I love you发送进去赋值给line模式coroutine不在其中不打印循环再次挂起在yieldsearch.send(Dont you love me?)同上coroutine不在其中不打印search.send(I love coroutine instead!)coroutine命中打印I love coroutine instead!。注意send()的语义发送的值会被yield接收同时send()本身也会推进协程继续执行到下一个yield挂起点——这正是它和纯传值不同的地方。仓库中 code/2.7/23_coroutine.py 完整复刻了这段逻辑Python 2.7 版本使用print语句读者可以直接执行验证python code/2.7/23_coroutine.py该文件把调用过程封装进了main()运行结果与上文输出完全一致。第四步为什么必须先调用next()原文档特别强调了一个初学者最容易困惑的问题发送的值会被yield接收。我们为什么要运行next()方法呢这样做正是为了启动一个协程。原因在于协程函数体内的代码并不会在创建对象时立刻执行。就像生成器一样代码是惰性的——必须通过next()推进到第一个yield表达式处协程才真正就位之后send()发送的值才有接收者。换句话说next(search)让协程执行到yield处并挂起此后每次send(value)都会唤醒协程让yield表达式的值变为value继续执行到下一个yield再次挂起。原文档的结论是必须通过next()方法来执行yield表达式协程才能响应后续的send()调用。在 Python 3 中send(None)与next()等价也可以用来启动协程——next()本质就是send(None)的语法糖这是生成器协议的标准行为可在 Python 官方文档中确认。第五步用close()关闭协程当协程不再需要时可以调用close()方法关闭它。关闭后协程将释放自身再次对它send()会抛出StopIteration异常。原文档示例search grep(coroutine) search.close()close()的作用原理是在协程挂起的yield处抛出GeneratorExit异常如果协程没有捕获它本例中while True循环会因此终止协程便正式结束。这保证了一个永远while True的协程能够被外部主动终止而不会泄漏资源。结合仓库源码协程与生成器的完整知识地图在《Python进阶》仓库中协程并不是孤立的知识点它与多个章节互为表里book/DataStructures/generators.md协程的上游知识。这里详细讲解了可迭代对象、迭代器、迭代三者的区别以及next()、iter()的用法和StopIteration异常的含义。理解生成器只能迭代一次for循环会自动捕获StopIteration这些特性是理解协程挂起/唤醒机制的前提book/DataStructures/README.md协程所属的数据结构章节入口本主题在该章节中排在生成器之后nav_order: 2正是先生成器、后协程的学习脉络book/Syntax/context_managers.md协程的应用延伸。该章节展示了用contextmanager装饰器配合生成器实现上下文管理器函数体内yield f之前的代码在进入with块时执行yield之后的代码在退出时执行——这正是把函数暂停/恢复能力与协程同源的机制用于资源管理的经典范式code/2.7/23_coroutine.py协程的可执行样例。仓库 code/README.md 说明code/2.7/目录下的代码为 Python 2.7 专用版本而书文中夹带的代码则保证兼容 Python 2/3读者可按需取舍。从协程走向更广阔的异步世界本主题只是协程的入门。原文档最后推荐了 David Beazley 关于协程的著名演讲A Curious Course on Coroutines and Concurrency其中涵盖协程的分发dispatch、流水线pipeline、扇出fan-out等高级模式。若想继续深入可以沿着两条路线阅读本仓库相邻章节先巩固 book/DataStructures/generators.md 的生成器协议再通过 book/Syntax/context_managers.md 观察yield挂起机制在实际工程中的应用对比 Python 3 的现代写法理解消费者协程 显式推进这一经典模型后再去看yield from和async/await就会轻松许多——它们解决的是同一类问题只是语法和调度方式更高级。小结本文完整还原了《Python进阶》协程章节的讲解脉络并补充了仓库源码层面的印证生成器用yield产出值协程用(yield)接收值next()负责启动协程并推进到第一个挂起点是send()生效的前提send(value)既向协程注入数据又推进协程执行到下一个yieldclose()用于主动终止一个无限循环的协程实战代码见 code/2.7/23_coroutine.py相关理论见 book/DataStructures/generators.md。掌握启动—喂值—挂起—再喂值—关闭这一完整生命周期你就真正理解了 Python 协程的核心机制也拿到了进入异步编程世界的第一把钥匙。赞分享教程文档教育【免费下载链接】interpy-zh《Python进阶》Intermediate Python - Chinese Version项目地址https://gitcode.com/gh_mirrors/in/interpy-zh点击查看免费下载相关推荐FastAPI 依赖注入进阶用 yield 编写带清理逻辑的依赖数据库会话、退出码与作用域详解FastAPI 依赖注入进阶用 yield 编写带清理逻辑的依赖数据库会话、退出码与作用域详解 本指南以 FastAPI 官方教程中「依赖与 yield后端Web框架API设计verilog2factorio命令行参数详解定制你的蓝图生成过程verilog2factorio命令行参数详解定制你的蓝图生成过程 verilog2factorio是一款将Verilog硬件描述语言编译为Factorio蓝Python数据结构操作进阶指南Python数据结构操作进阶指南 本文全面介绍了Python中高级数据结构操作技巧涵盖列表去重与唯一性检查、字典操作与键值处理、集合运算与数据合并、数据分组与教程文档上一篇Texture-vs-Shape模型训练秘籍超参数设置与Stylized-ImageNet训练技巧终极指南下一篇StatsD 对接 Graphite 配置完全指南Storage Schemas 与 Storage Aggregation 实战详解创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表