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中你不知道的gzip高级用法分享

《Python中你不知道的gzip高级用法分享》在当今大数据时代,数据存储和传输成本已成为每个开发者必须考虑的问题,Python内置的gzip模块提供了一种简单高效的解决方案,下面小编就来和大家详细讲... 目录前言:为什么数据压缩如此重要1. gzip 模块基础介绍2. 基本压缩与解压缩操作2.1 压缩文

Python设置Cookie永不超时的详细指南

《Python设置Cookie永不超时的详细指南》Cookie是一种存储在用户浏览器中的小型数据片段,用于记录用户的登录状态、偏好设置等信息,下面小编就来和大家详细讲讲Python如何设置Cookie... 目录一、Cookie的作用与重要性二、Cookie过期的原因三、实现Cookie永不超时的方法(一)

Python内置函数之classmethod函数使用详解

《Python内置函数之classmethod函数使用详解》:本文主要介绍Python内置函数之classmethod函数使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地... 目录1. 类方法定义与基本语法2. 类方法 vs 实例方法 vs 静态方法3. 核心特性与用法(1编程客

Python函数作用域示例详解

《Python函数作用域示例详解》本文介绍了Python中的LEGB作用域规则,详细解析了变量查找的四个层级,通过具体代码示例,展示了各层级的变量访问规则和特性,对python函数作用域相关知识感兴趣... 目录一、LEGB 规则二、作用域实例2.1 局部作用域(Local)2.2 闭包作用域(Enclos

Python实现对阿里云OSS对象存储的操作详解

《Python实现对阿里云OSS对象存储的操作详解》这篇文章主要为大家详细介绍了Python实现对阿里云OSS对象存储的操作相关知识,包括连接,上传,下载,列举等功能,感兴趣的小伙伴可以了解下... 目录一、直接使用代码二、详细使用1. 环境准备2. 初始化配置3. bucket配置创建4. 文件上传到os

使用Python实现可恢复式多线程下载器

《使用Python实现可恢复式多线程下载器》在数字时代,大文件下载已成为日常操作,本文将手把手教你用Python打造专业级下载器,实现断点续传,多线程加速,速度限制等功能,感兴趣的小伙伴可以了解下... 目录一、智能续传:从崩溃边缘抢救进度二、多线程加速:榨干网络带宽三、速度控制:做网络的好邻居四、终端交互

Python中注释使用方法举例详解

《Python中注释使用方法举例详解》在Python编程语言中注释是必不可少的一部分,它有助于提高代码的可读性和维护性,:本文主要介绍Python中注释使用方法的相关资料,需要的朋友可以参考下... 目录一、前言二、什么是注释?示例:三、单行注释语法:以 China编程# 开头,后面的内容为注释内容示例:示例:四

Python中win32包的安装及常见用途介绍

《Python中win32包的安装及常见用途介绍》在Windows环境下,PythonWin32模块通常随Python安装包一起安装,:本文主要介绍Python中win32包的安装及常见用途的相关... 目录前言主要组件安装方法常见用途1. 操作Windows注册表2. 操作Windows服务3. 窗口操作

Python中re模块结合正则表达式的实际应用案例

《Python中re模块结合正则表达式的实际应用案例》Python中的re模块是用于处理正则表达式的强大工具,正则表达式是一种用来匹配字符串的模式,它可以在文本中搜索和匹配特定的字符串模式,这篇文章主... 目录前言re模块常用函数一、查看文本中是否包含 A 或 B 字符串二、替换多个关键词为统一格式三、提

python常用的正则表达式及作用

《python常用的正则表达式及作用》正则表达式是处理字符串的强大工具,Python通过re模块提供正则表达式支持,本文给大家介绍python常用的正则表达式及作用详解,感兴趣的朋友跟随小编一起看看吧... 目录python常用正则表达式及作用基本匹配模式常用正则表达式示例常用量词边界匹配分组和捕获常用re