Python生成器 (Generators in Python)

2023-12-30 14:04
文章标签 python 生成器 generators

本文主要是介绍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。

这篇关于Python生成器 (Generators in Python)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/553065

相关文章

python: 多模块(.py)中全局变量的导入

文章目录 global关键字可变类型和不可变类型数据的内存地址单模块(单个py文件)的全局变量示例总结 多模块(多个py文件)的全局变量from x import x导入全局变量示例 import x导入全局变量示例 总结 global关键字 global 的作用范围是模块(.py)级别: 当你在一个模块(文件)中使用 global 声明变量时,这个变量只在该模块的全局命名空

【Python编程】Linux创建虚拟环境并配置与notebook相连接

1.创建 使用 venv 创建虚拟环境。例如,在当前目录下创建一个名为 myenv 的虚拟环境: python3 -m venv myenv 2.激活 激活虚拟环境使其成为当前终端会话的活动环境。运行: source myenv/bin/activate 3.与notebook连接 在虚拟环境中,使用 pip 安装 Jupyter 和 ipykernel: pip instal

【机器学习】高斯过程的基本概念和应用领域以及在python中的实例

引言 高斯过程(Gaussian Process,简称GP)是一种概率模型,用于描述一组随机变量的联合概率分布,其中任何一个有限维度的子集都具有高斯分布 文章目录 引言一、高斯过程1.1 基本定义1.1.1 随机过程1.1.2 高斯分布 1.2 高斯过程的特性1.2.1 联合高斯性1.2.2 均值函数1.2.3 协方差函数(或核函数) 1.3 核函数1.4 高斯过程回归(Gauss

【学习笔记】 陈强-机器学习-Python-Ch15 人工神经网络(1)sklearn

系列文章目录 监督学习:参数方法 【学习笔记】 陈强-机器学习-Python-Ch4 线性回归 【学习笔记】 陈强-机器学习-Python-Ch5 逻辑回归 【课后题练习】 陈强-机器学习-Python-Ch5 逻辑回归(SAheart.csv) 【学习笔记】 陈强-机器学习-Python-Ch6 多项逻辑回归 【学习笔记 及 课后题练习】 陈强-机器学习-Python-Ch7 判别分析 【学

nudepy,一个有趣的 Python 库!

更多资料获取 📚 个人网站:ipengtao.com 大家好,今天为大家分享一个有趣的 Python 库 - nudepy。 Github地址:https://github.com/hhatto/nude.py 在图像处理和计算机视觉应用中,检测图像中的不适当内容(例如裸露图像)是一个重要的任务。nudepy 是一个基于 Python 的库,专门用于检测图像中的不适当内容。该

pip-tools:打造可重复、可控的 Python 开发环境,解决依赖关系,让代码更稳定

在 Python 开发中,管理依赖关系是一项繁琐且容易出错的任务。手动更新依赖版本、处理冲突、确保一致性等等,都可能让开发者感到头疼。而 pip-tools 为开发者提供了一套稳定可靠的解决方案。 什么是 pip-tools? pip-tools 是一组命令行工具,旨在简化 Python 依赖关系的管理,确保项目环境的稳定性和可重复性。它主要包含两个核心工具:pip-compile 和 pip

HTML提交表单给python

python 代码 from flask import Flask, request, render_template, redirect, url_forapp = Flask(__name__)@app.route('/')def form():# 渲染表单页面return render_template('./index.html')@app.route('/submit_form',

Python QT实现A-star寻路算法

目录 1、界面使用方法 2、注意事项 3、补充说明 用Qt5搭建一个图形化测试寻路算法的测试环境。 1、界面使用方法 设定起点: 鼠标左键双击,设定红色的起点。左键双击设定起点,用红色标记。 设定终点: 鼠标右键双击,设定蓝色的终点。右键双击设定终点,用蓝色标记。 设置障碍点: 鼠标左键或者右键按着不放,拖动可以设置黑色的障碍点。按住左键或右键并拖动,设置一系列黑色障碍点

Python:豆瓣电影商业数据分析-爬取全数据【附带爬虫豆瓣,数据处理过程,数据分析,可视化,以及完整PPT报告】

**爬取豆瓣电影信息,分析近年电影行业的发展情况** 本文是完整的数据分析展现,代码有完整版,包含豆瓣电影爬取的具体方式【附带爬虫豆瓣,数据处理过程,数据分析,可视化,以及完整PPT报告】   最近MBA在学习《商业数据分析》,大实训作业给了数据要进行数据分析,所以先拿豆瓣电影练练手,网络上爬取豆瓣电影TOP250较多,但对于豆瓣电影全数据的爬取教程很少,所以我自己做一版。 目

【Python报错已解决】AttributeError: ‘list‘ object has no attribute ‘text‘

🎬 鸽芷咕:个人主页  🔥 个人专栏: 《C++干货基地》《粉丝福利》 ⛺️生活的理想,就是为了理想的生活! 文章目录 前言一、问题描述1.1 报错示例1.2 报错分析1.3 解决思路 二、解决方法2.1 方法一:检查属性名2.2 步骤二:访问列表元素的属性 三、其他解决方法四、总结 前言 在Python编程中,属性错误(At