python 生成器

127 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第18天,点击查看活动详情

生成器

信息隐藏的一个感知风险是,阻止客户端程序直接访问关键数据结构会导致不可接受的效率损失。在数据抽象的早期,许多人担心引入无关的成本函数或方法调用。现代编译技术使这个问题变得毫无意义。一个更严重的问题是,客户端程序将被迫使用低效的算法。

考虑图 10-7 中grade_report的实现,调用course.get_students创建并返回大小为 n 的列表,其中 n 是学生数。对于一个班级的成绩簿来说,这可能不是问题,但想象一下跟踪170万参加SAT的高中生的成绩。当列表已存在时,创建该大小的新列表是一个显著的低效率。一种解决方案是放弃抽象并允许grade_report自径直访问实例变量 course.学生,但这会违反信息隐藏。幸运的是,有一个更好的解决方案。

艾古尔 10-9 中的代码。将班级 Grades 中的get_students函数替换为使用一种我们尚未见过的语句的函数:yield 语句。

任何包含 yield 语句的函数定义都以特殊方式进行处理。产量的存在告诉Python系统该函数是一个生成器。发生器通常与

对于语句,如

image.png

如图 10-7 所示。

image.png

在使用生成器的 for 循环的第一次迭代开始时,生成器被调用并运行,直到第一次执行 yield 语句,此时它返回表达式。在下一次迭代中,生成器在 yield 语句后立即恢复执行,所有局部变量都绑定到执行 yield 语句时绑定到的对象,并再次运行,直到执行 yield 语句。它继续这样做,直到它用完了要执行的代码或执行返回语句,此时循环将退出。

艾古雷10-9中get_students的版本。允许程序员使用 for 循环来迭代 Grades 类型对象中的学生,就像他们可以使用 for 循环来迭代内置类型的元素(如 list)一样。例如,代码

image.png

打印

image.png

因此,Eigure 10-7 中

image.png

不必更改即可利用包含新实现的get_students的班级成绩版本。(当然,大多数依赖于get_students返回列表的代码将不再有效。相同的 for 循环可以循环访问 get_students 提供的值,而不管get_students是返回值列表还是一次生成一个值。一次生成一个值将更有效,因为不会创建包含学生的新列表。

练习:将符合规范的发生器添加到“等级”

image.png