Python生成器 (Generators in Python)

Generators in Python

文章目录

  • Generators in Python
    • Introduction 导言
    • 贯穿全文的几句话
    • 为什么 Python 有生成器Generator?
    • 如何获得生成器Generator?
      • 1. 生成器表达式 Generator Expression
      • 2. 使用yield定义生成器Generator
    • 更多Generator应用实例
      • 表示无限的数据流infinite stream of data
      • 将多个生成器generators组成管道pipeline
    • Conclusion 结论

Introduction 导言

生成器generator是 Python 中用来生成迭代器Iterators的一个方便而强大的工具。本篇文章将通过一些示例来解释和深入介绍 Python 中的生成器generators。

如果您还没有完全理解 Itreators,不用担心,请阅读此篇文章。

贯穿全文的几句话

  • 只要一个函数function中使用了 yield 这个关键字,就代表这个函数function每次调用时返回的是一个生成器对象 generator object。这个生成器对象的类型是<class ‘generator’>。

  • 包含 yield 语句的函数function本身并不是生成器generator,它仍然是一个函数function。生成器generator是一个类class,而不是函数function。

  • 生成器generator是迭代器Iterator的一个子类subclass。

  • 生成器generator保存的是产生item的生成方法/算法,而不是items。

  • next() 函数只能用于生成器generator类型。不能用于函数function。

def func():yield "Hello"print(func)  # <function func at 0x10d55c0d0>
print(type(func))  # <class 'function'>g1 = func()
g2 = func()
print(id(g1), id(g2))  # 4519738272 4519739168
print(g1)  # <generator object func at 0x10d65bba0>
print(type(g1))  # <class 'generator'>
print(next(g1))  # Hello

为什么 Python 有生成器Generator?

我们可以通过在 Python 类class中实现implementing __iter__()__next__() 特殊方法special methods来获得迭代器Iterator。不过,这种方法有点复杂,尽管它有助于理解迭代器Iterators的真正工作原理。

通过生成器generators创建迭代器Iterators是一种更好、更方便的方法。事实上,生成器就是迭代器的子类the Generator is a subclass of the Iterator。

Iterable可迭代对象、Iterator迭代器 和 Generator生成器 的关系如下:

在这里插入图片描述

如上图所示,Iterator 是 Iterable 的子类,Generator 是 Iterator 的子类。

# 源码在_collections_abc.py
class Iterable(metaclass=ABCMeta):@abstractmethoddef __iter__(self): ...
# 源码在_collections_abc.py
class Iterator(Iterable):@abstractmethoddef __next__(self): raise StopIterationdef __iter__(self): return self
# 源码在_collections_abc.py
class Generator(Iterator):def __iter__(self):return selfdef __next__(self):"""Return the next item from the generator.When exhausted, raise StopIteration."""return self.send(None)@abstractmethoddef send(self, value):"""Send a value into the generator.Return next yielded value or raise StopIteration."""raise StopIteration@abstractmethoddef throw(self, typ, val=None, tb=None):"""Raise an exception in the generator.Return next yielded value or raise StopIteration."""...def close(self):"""Raise GeneratorExit inside generator."""...

生成器(Generator)与迭代器(Iterator)具有相同的作用,用于保存一个知道如何生成所需元素的方法method。在Python中操作一个大的列表是非常耗时的。如果我们每次只需要获取一个元素element,那么生成器generator就是一个很好的选择,它可以减少时间和空间成本。

在 Python 中,只要一个函数function中使用了 yield 这个关键字,就代表这个函数function每次调用时都是返回一个生成器对象 generator object,注意:包含 yield 语句的函数function本身并不是生成器generator,它仍然是一个函数function。生成器generator是一个类class,而不是函数function。而 yield 的作用就相当于让 Python 帮我们把一个“串行”的逻辑转换成 iterator 的形式。

生成器generator都是Iterator迭代器对象。

如何获得生成器Generator?

1. 生成器表达式 Generator Expression

生成器表达式generator expression是获取生成器generator的最简单方法。它与 列表推导式list comprehensions 非常相似。我们只需将括号brackets改为小括号parentheses。

my_list = [i for i in range(8)]
my_generator = (i for i in range(8))print(my_list)
print(my_generator)# [0, 1, 2, 3, 4, 5, 6, 7]
# <generator object <genexpr> at 0x7f8fc3ec9a40>

由于生成器generator保存的是item生成方法而不是items,因此我们需要使用 next() 函数逐个获取项目get items one by one,这与迭代器Iterator相同。当所有项目items都生成后, next() 函数将引发 StopIteration 错误信息。当然,我们也可以使用 for 循环来获取生成器generator中的项目items。

2. 使用yield定义生成器Generator

如果一个函数function包含 yield 语句,它就可以产生生成器generators。

def my_generator(maximum):n = 0while n < maximum:n += 1yield nreturn 'Done'g = my_generator(maximum=5)
print(g)  # <generator object my_generator at 0x10e269ba0>
print(next(g))  # 1
print(next(g))  # 2
print(next(g))  # 3
print(next(g))  # 4
print(next(g))  # 5
next(g)
# Traceback (most recent call last):
#   File "/usr/lib/python3.9/code.py", line 15, in <module>
#     next(g)
# StopIteration: Done

yield 表示 “产生”或“生成”produce。当程序执行到 yield 语句时,就会 "生产produce"一个值即项目item,而 next() 函数function就会在此暂停pauses there执行,等待下一次调用。

当我们再次使用 next() 函数function对生成器对象generator object进行调用,它会让生成器对象generator object从上一次暂停的位置继续执行,直到遇到下一个 yield 语句或者执行结束。

普通函数normal functions 与 包含 yield 的函数functions including yield 的主要区别在于执行流程execution flow

  • 普通函数按顺序执行executes sequentially,并在遇到 return 语句statement或到达最后一行final line时返回结果。
  • 包括 yield 的函数会在调用 next() 时执行,并在遇到 yield 语句时返回。再次调用 next() 时,将从上次暂停的 yield 语句处继续执行。

有一个例子:

def example():print('step 1')yield 1print('step 2')yield 2print('step 3')yield 3g = example()next(g)
# step 1
# 1
next(g)
# step 2
# 2
next(g)
# step 3
# 3
next(g)
# Traceback (most recent call last):
#   File "/usr/lib/python3.9/code.py", line 21, in <module>
#     next(g)
# StopIteration

注:包含 yield 语句的函数本身并不是生成器generator。它仍然是一个函数function,但每次调用这个函数function时都可以返回一个生成器对象return a generator,这个生成器对象的类型是<class ‘generator’>。生成器generator是一个类class,而不是函数function。(正如我们之前所说,生成器generator是迭代器Iterator的一个子类subclass)。

next() 只能用于生成器generator类型。不能用于函数function。

def my_generator(maximum):n = 0while n < maximum:yield nreturn 'Done'print(type(my_generator))  # <class 'function'>print(type(my_generator(5)))  # <class 'generator'>print(my_generator(5))  # <generator object my_generator at 0x10bc42ba0>print(next(my_generator(5)))  # 0print(next(my_generator))
# Traceback (most recent call last):
#   File "/usr/lib/python3.9/code.py", line 15, in <module>
#     print(next(my_generator))
# TypeError: 'function' object is not an iterator

更多Generator应用实例

到目前为止,我们知道生成器generators可以帮助我们保存生成项目items的算法,并在需要时生成项目items。与包含所有项目items的庞大列表list相比,生成器可以减少时间和内存成本。

表示无限的数据流infinite stream of data

事实上,生成器generator甚至可以表示无限的数据流infinite stream of data。例如:

def fibonacci():x, y = 0, 1while True:x, y = y, x + yyield xfib = fibonacci()
print(next(fib))
print(next(fib))
print(next(fib))
print(next(fib))
print(next(fib))
print(next(fib))
# ...

fib 是一个无限生成器infinite generator,我们可以根据自己的需要使用它。

将多个生成器generators组成管道pipeline

生成器generators的另一个有趣应用interesting application是,我们可以将一系列生成器generators组合起来,得到一个新的生成器generator,这在技术technically上被称为 “管道pipeline”。

def times_two(nums):for n in nums:yield n * 2def natural_number(maximum):x = 0while x < maximum:yield xx += 1p = times_two(natural_number(10))
print(type(p))  # <class 'generator'>
print(next(p))  # 0
print(next(p))  # 2
print(next(p))  # 4
print(next(p))  # 6
print(next(p))  # 8
print(next(p))  # 10
print(next(p))  # 12
# ...

如上例所示,我们可以使用现有的两个生成器generators来定义一个新的生成器generator。这不是很好吗?

Conclusion 结论

生成器Generator是 Python 中一种非常有用的机制useful mechanism,可以减少时间reduce time和内存开销memory costs。它保存的是产生项item的算法algorithm而不是项items。我们还可以使用生成器generators生成produce无限的数据流infinite data stream和管道pipelines。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/586231.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

车牌识别技术,如何用python识别车牌号

目录 一.前言 二.运行环境 三.代码 四.识别效果 五.参考 一.前言 车牌识别技术&#xff08;License Plate Recognition, LPR&#xff09;在交通计算机视觉&#xff08;Computer Vision, CV&#xff09;领域具有非常重要的研究意义。以下是该技术的一些扩展说明&#xff1…

Day20 222完全二叉树的节点个数 110平衡二叉树 257二叉树的所有路径

222 完全二叉树的结点个数 本题先不把它当成完全二叉树来看&#xff0c;用广度优先和深度优先搜索分别遍历&#xff0c;也能达到目的&#xff0c;只要将之前的代码稍加修改即可。注意后序遍历时的result要加上自身本身的那个结点。 //后序递归遍历 class Solution { public:in…

STL——集合算法

算法简介&#xff1a; set_intersection // 求两个容器的交集set_union // 求两个容器的并集set_difference // 求两个容器的差集 1.set_intersection 函数原型&#xff1a; set_intersection(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest);…

【办公技巧】怎么批量提取文件名到excel

Excel是大家经常用来制作表格的文件&#xff0c;比如输入文件名&#xff0c;如果有大量文件需要输入&#xff0c;用张贴复制或者手动输入的方式还是很费时间的&#xff0c;今天和大家分享如何批量提取文件名。 打开需要提取文件名的文件夹&#xff0c;选中所有文件&#xff0c…

iptables 防火墙(二)

目录 1. SNAT 策略及应用 1.1 SNAT策略概述 1. 只开启路由转发&#xff0c;未设置地址转换的情况 2. 开启路由转发&#xff0c;并设置SNAT转换的情况 1.2 SNAT策略的应用 1. 2.1 共享固定IP上网 &#xff08;1&#xff09;打开网关的路由转发 &#xff08;2&#xff09;…

MongoDB 概念介绍

1、MongoDB 应用场景 传统的关系型数据库&#xff0c;在数据操作的"三高"需求以及应对Web2.0的网站需求面前&#xff0c;显得力不从心。 High performance -对数据库高并发读写的需求。Huge Storage -对海量数据的高效率存储和访问的需求。High Scalability &&…

Java核心知识点1-java和c++区别、隐式和显示类型转换

java和c区别 java通过虚拟机实现跨平台特性&#xff0c;但c依赖于特定的平台。java没有指针&#xff0c;它的引用可以理解为安全指针&#xff0c;而c和c一样具有指针。java支持自动垃圾回收&#xff0c;而c需要手动回收。java不支持多重继承&#xff0c;只能通过实现多个接口来…

C++进阶--二叉树进阶(二叉搜索树)

二叉树进阶&#xff08;二叉搜索树&#xff09; 一、二叉搜索树1.1 二叉搜索树的概念 二、二叉搜索树的结构2.1 结点结构2.2 树结构 三、二叉搜索树的操作&#xff08;非递归&#xff09;3.1 二叉搜索树的插入3.2 二叉搜索树的查找3.3 二叉搜索树的中序遍历3.4 二叉搜索树的删除…

c++学习笔记-提高篇-STL-函数对象

目录 一、函数对象 二、函数对象使用 三、谓词 1、概念 2、一元谓词 3、二元谓词 插入一条sort函数源码 四、内建函数对象 1.基本概念 2、算数仿函数 3、关系仿函数 4、逻辑仿函数 一、函数对象 函数对象概念 &#xff08;1&#xff09;重载函数调用操作符的类&a…

WPF+Halcon 培训项目实战(11):HS组件封装

文章目录 前言相关链接项目专栏运行环境匹配图片封装组件新增类库项目选择依赖顺序并添加Nuget修改原本矩形方法运行结果&#xff1a; 对矩形进行抽象封装抽象基类矩形抽象改造 圆形抽象封装代码运行结果 前言 为了更好地去学习WPFHalcon&#xff0c;我决定去报个班学一下。原…

Baumer工业相机堡盟工业相机如何通过NEOAPI SDK设置相机的固定帧率(C++)

Baumer工业相机堡盟工业相机如何通过NEOAPI SDK设置相机的固定帧率&#xff08;C&#xff09; Baumer工业相机Baumer工业相机的固定帧率功能的技术背景CameraExplorer如何查看相机固定帧率功能在NEOAPI SDK里通过函数设置相机固定帧率 Baumer工业相机通过NEOAPI SDK设置相机固定…

harmonyOS Column组件通过space属性设置内部元素间距

例如 我们代码如下 import router from ohos.router Entry Component struct Index {build() {Row() {Column() {Text("年后")Text("一起")Text("旅游")}.width(100%)}.height(100%)} }运行之后 元素都粘连到一起 显然不太好看 我们就可以通过…

PM大逃亡

欢迎来到程序小院 PM大逃亡 玩法&#xff1a;点击白色的小鬼&#xff0c;滑动鼠标移动&#xff0c;不要碰到黑色的怪物&#xff0c; 怪物会越来越多&#xff0c;看看你能坚持多久&#xff0c;快去大逃亡吧^^。开始游戏https://www.ormcc.com/play/gameStart/233 html <div…

分享Python采集40个NET整站程序源码,总有一款适合您

分享Python采集40个NET整站程序源码&#xff0c;总有一款适合您 Python采集的40个NET整站程序源码下载链接&#xff1a;https://pan.baidu.com/s/1z54JHJkFYa4Kx2oBtPrn_w?pwd2ta4 提取码&#xff1a;2ta4 商品评论网站系统 小孔子内容管理系统XkCms V2.0 友间别墅整站程…

【win10】解决重装系统后笔记本无法调节亮度的问题

问题描述 笔记本重装系统后发现之前的fn快捷键调节亮度的功能無了&#xff0c;检查过后发现n卡控制面板&#xff0c;电源选项这些能调节屏幕亮度的地方一个都不行。笔记本一直是最强亮度非常伤眼睛。 问题分析 重装系统后发生这种情况大概率是因为之前的显卡驱动没了&#…

【rar转zip】如何将rar文件轻松转换成zip

今天和大家分享三个rar压缩包改成zip格式的方法&#xff0c;希望能够帮助到大家&#xff01; 方法一&#xff1a; 直接修改rar压缩包的后缀名变为zip&#xff0c;就可以修改压缩包文件格式了 方法二&#xff1a; 先将rar压缩包解压出来&#xff0c;然后再将解压出的文件进行…

【MATLAB】BiGRU神经网络时序预测算法

有意向获取代码&#xff0c;请转文末观看代码获取方式~也可转原文链接获取~ 1 基本定义 BiGRU神经网络时序预测算法是一种基于双向门控循环单元&#xff08;GRU&#xff09;的多变量时间序列预测方法。该方法结合了双向模型和门控机制&#xff0c;旨在有效地捕捉时间序列数据中…

git 常用操作合集

✨专栏介绍 在当今数字化时代&#xff0c;Web应用程序已经成为了人们生活和工作中不可或缺的一部分。而要构建出令人印象深刻且功能强大的Web应用程序&#xff0c;就需要掌握一系列前端技术。前端技术涵盖了HTML、CSS和JavaScript等核心技术&#xff0c;以及各种框架、库和工具…

CCSK认证:开启云安全领域的黄金大门

&#x1f31f;你是否对云安全领域充满热情&#xff1f;是否希望提升自己在云安全领域的专业性和竞争力&#xff1f;CCSK认证是你的不二之选&#xff01; &#x1f525;CCSK简介&#xff1a; CCSK是国际云安全联盟&#xff08;Cloud Security Alliance&#xff0c;CSA&#xff…

【前端基础】——原型与原型链详解,看一篇即可【图文版】

前言 本文旨在通过图文的方式&#xff0c;一步步回顾原型链的整个流程是如何运作的&#xff0c;如果你刚好在电脑旁边&#xff0c;不妨跟着我的思路&#xff0c;一起走一遍敲一遍代码流程&#xff0c;你会发现原型链并没有你想的那么复杂。 new关键字 我们先看这一个代码&am…