当前位置: 首页 > news >正文

深入探秘Python生成器:揭开神秘的面纱

一、问题起源:

想象一下,您掌握了一种魔法,在代码世界里,您可以轻松呼唤出一个整数。然而,事情并不总是看起来那样简单。在Python的奇妙王国中,我遇到了一个有趣的谜题:

def tst():try:print('hello world')return 1except:yield 2
print(tst())
type(tst())

表面上,这段代码看起来像是在进行一个简单的问候和返回神秘数字1的仪式。但是,执行后,却揭晓了一个出乎意料的结果:

<generator object tst at 0x00000255F7E039F0>
generator

这个不是预期中的整数!而是一种被称为生成器的强大生物。那么,这是如何发生的呢?

二、魔法解密:为何它是生成器?

一段代码的命运,在Python领域里,是由它出生(定义)的时刻就注定了。就像预言中说的,函数的行为被它的定义方式固定下来,而非仅仅由它实际运行时的动作决定。
Python中的先知们(编译器),在瞥见函数的定义时,会使用他们的预言之眼(分析功能),寻找隐藏于代码深处的yield这个关键词符。发现了yield,哪怕它藏在一条不曾通往的冷僻小径上(逻辑上不可达的代码块),编译器也会宣告:这是一个生成器!
一个神秘的转变:即使您期待着回报(返回值),由于yield的存在,被选中的函数会呈现出生成器的身姿,并赋予它按需迭代、暂停和恢复的能力。
这是因为 Python 的函数定义的语义决定了在编译函数的时候解释器会如何处理它。
在 Python 中,函数如何行为取决于函数的定义而不仅仅是实际运行时的行为。当 Python 的编译器遇到一个函数定义时,它会检查函数体内的语句。如果它发现了 yield 关键字,不管这个 yield 是否在逻辑上可达(即不管它是否在 try 块还是 except 块,或者它是否在某个条件判断很少为真的代码分支中),它都会将这个函数标记为生成器函数。
这意味着一旦函数体中出现 yield,Python 就会创建生成器对象而不是直接执行函数体并返回单一的结果。

三、神秘仪式:为何print未被宣读?

这个生成器仪式的初次召唤(首次调用函数)并不意味着立即展现魔法(执行函数体内的代码),而是颁发一个神秘的标记(生成器对象)。这个标记,好像是一个尚未开启的宝箱,装载着即将展开的奇妙冒险。
迭代这个标记(调用生成器对象的next()方法),就像翻开宝箱的锁,魔法(函数体的代码)才会启动,直到遇到第一个yield魔法符(表达式)为止。
想要领略这段冒险,就请看以下的仪式演示:

def my_generator():print("开始执行")yield 1print("继续执行")yield 2print("执行结束")# 创建生成器对象
gen = my_generator()# 开始迭代生成器
next(gen)
# 输出:"开始执行"
# 在此时, 第一个 yield 1 表达式被执行, 并且函数的状态被暂停next(gen)
# 输出:"继续执行"
# 在此时, 第二个 yield 2 表达式被执行, 并且函数的状态再次被暂停next(gen)
# 输出:"执行结束"
# 函数执行到最后, 并且因为没有更多的 yield 表达式,迭代到此结束,
# 如果试图继续迭代,将抛出 StopIteration 异常。

这是因为生成器函数在首次被调用并返回生成器对象时,并不会执行任何函数体内部的代码,它只是返回一个生成器对象。这个生成器对象可以理解为一个有待执行的函数体。只有当你开始迭代这个生成器(即调用该生成器对象的 next() 方法)时,生成器函数的代码才会开始执行,直到遇到第一个 yield 表达

四、最终揭示

  • 即使很隐秘,yield魔法符号的存在,会让一个函数被赋予生成器的身份。
  • 魔法的初次召唤(生成器函数首次调用)仅仅是交付了一个未来冒险的符记(生成器对象),不触发任何神秘力量(不执行函数体内的代码)。
  • 开启这个冒险(使用next()方法迭代生成器对象)才真正激活了仪式中的法术(函数体内的代码),并把我们引领至第一个法术停顿点(yield)。
http://www.lryc.cn/news/329088.html

相关文章:

  • 红队攻防渗透技术实战流程:红队目标信息收集之批量信息收集
  • 【vue3学习笔记(二)】(第141-143节)初识setup;ref函数_处理基本类型;ref函数_处理对象类型
  • 若依框架学习使用
  • 蓝桥杯_数学模板
  • 稀碎从零算法笔记Day31-LeetCode:接雨水
  • 微前端的使用和注意事项 - qiankun
  • uniapp微信小程序消息订阅详解
  • git 查看文件夹结构树
  • 设计模式一详解
  • python 进程、线程、协程基本使用
  • SQLite3进行数据库各项常用操作
  • Debian GNU/Linux 安装docker与docker compose
  • 图片标注编辑平台搭建系列教程(2)——fabric.js简介
  • Debian linux版本下运行的openmediavault网盘 千兆网卡升级万兆
  • 前端 CSS 经典:grid 栅格布局
  • 多输入多输出通道
  • http响应练习—在服务器端渲染html(SSR)
  • C++(8): std::deque的使用
  • openwrt开发包含路由器基本功能的web问题记录
  • HarmonyOS ArkTS 骨架屏加载显示(二十五)
  • Ruoyi-Cloud-Plus_使用Docker部署分布式微服务系统_环境准备_001---SpringCloud工作笔记200
  • RN封装的底部向上弹出的弹出层组件
  • 基于深度学习YOLOv8+PyQt5的水底海底垃圾生物探测器检测识别系统(源码+数据集+配置说明)
  • SpringBoot集成WebSocket实现简单的多人聊天室
  • 如何使用固定公网地址远程访问内网Axure RP生成的网站原型web页面
  • 蓝桥杯习题
  • AMS概念以及面试相关整理
  • Vmware下减小Ubuntu系统占用系统盘大小
  • 面试题-Elasticsearch集群架构和调优手段(超全面)
  • python基础练习题6