Python教程(26)——Python迭代器和生成器详解

迭代器

Python中的迭代器是一种对象,它可以迭代(遍历)一个可迭代对象(比如列表、元组或字符串)的元素。迭代器用于实现迭代器协议,即包含 __iter__() 方法和 __next__() 方法。

迭代器的工作原理是每次调用 __next__() 方法时返回可迭代对象的下一个元素,当没有元素可迭代时,抛出 StopIteration 异常。

class MyIterator:def __init__(self, iterable):self.iterable = iterableself.index = 0def __iter__(self):return selfdef __next__(self):if self.index < len(self.iterable):result = self.iterable[self.index]self.index +=1return resultelse:raise StopIteration# 创建一个可迭代对象
my_list = [1, 2, 3, 4, 5]# 创建一个迭代器
my_iterator = MyIterator(my_list)# 使用迭代器遍历元素
for item in my_iterator:print(item)

值得注意的是,当迭代器耗尽后,如果再次使用迭代器来便利,将不会得到任何输出。
所以总的来说,迭代器是用于遍历可迭代对象的对象,它实现了迭代器协议,具有 __iter__()__next__() 方法。

可迭代对象

我们看迭代器好像和平时我们使用的列表、字典等数据结构一样,都可以遍历,那么列表、字典等数据结构是迭代器吗?

不好意思,他们不是迭代器,而是可迭代对象(iterable)。

可迭代对象(iterable)是指具有迭代行为的对象。当我们希望能够按照一定方式遍历对象中的元素时,我们可以将该对象称为可迭代对象。换句话说,可迭代对象是一种提供迭代能力的容器。
可迭代对象的特点是实现了 __iter__() 方法,这个方法返回一个迭代器(iterator)。迭代器是能够按照一定顺序生成下一个元素的对象。

在 Python 中,许多数据结构都是可迭代对象,比如列表、元组、集合、字典等。我们可以使用for循环对这些对象进行遍历。

同时,也可以使用内置的 iter() 函数将可迭代对象转换为迭代器。迭代器是可迭代对象的一种特殊形式,实现了 __iter__()__next__() 方法。迭代器可以使用 next() 函数来获取下一个元素,并且在没有元素可返回时引发 StopIteration 异常。

my_list = [1, 2, 3, 4, 5]  # 列表是可迭代对象
for item in my_list:print(item)my_iterator = iter(my_list)  # 使用iter()函数将列表这个可迭代对象转换为迭代器
print(next(my_iterator))  # 输出第一个元素
print(next(my_iterator))  # 输出第二个元素

在这个示例中,列表 my_list 是可迭代对象,它可以被 for 循环遍历。另外,我们还使用 iter() 函数将 my_list 转换为迭代器 my_iterator,并使用 next() 函数逐个访问其中的元素。

所以总的来说,可迭代对象是指具有迭行为的对象,它们实现了 __iter__() 方法。通过for循环或 iter() 函数,我们可以遍历这些对象的元素。

可迭代对象是指实现了 __iter__() 方法的对象,而迭代器是实现了 __iter__()__next__() 方法的对象,这个可以说是它们比较明显的区别。

for循环机制

从上面我们指定,列表、元组、集合、字典等数据结构是可迭代对象,并不是迭代器。而可迭代对象只实现了__iter__()方法,并不具有迭代(也就是返回下一个元素)的功能。那么很多同学可能就比较奇怪了,我们平时使用for循环遍历这个数据结构的时候,内部是怎么遍历的呢?

实际上在 Python 中,for循环在内部自动会调用 __iter__() 函数将可迭代对象转换为迭代器。用for循环遍历可迭代对象的实现机制为:

  • for循环首先会调用 __iter__() 函数,该函数会将可迭代对象转换为一个迭代器对象(如果对象本身就是迭代器,则不作转换)。
  • 接下来,for循环会调用迭代器对象的 __next__() 方法来获取下一个元素。如果迭代器对象没有下一个元素,会抛出 StopIteration 异常。
  • for循环会自动捕捉 StopIteration 异常,表示已经迭代完所有元素,循环将结束。

所以以下两个方法实际上是等价的。

my_string = "Hello"for char in my_string:print(char)

实际上完全等价于:

my_string = "Hello"
my_iterator = iter(my_string)print(next(my_iterator))  # 输出:H
print(next(my_iterator))  # 输出:e
print(next(my_iterator))  # 输出:l
print(next(my_iterator))  # 输出:l
print(next(my_iterator))  # 输出:o

生成器

生成器(Generator)是一种特殊的迭代器,它可以在迭代过程中动态地生成值,而不是一次性地将所有元素放在内存中。生成器使用 yield 关键字来定义,当生成器的代码块执行到 yield 语句时,就会暂停执行并返回一个值,下次调用时会从上次暂停的位置继续执行。这样可以在需要的时候生成值,而不是一次性生成所有的值。

def my_generator():yield 1yield 2yield 3# 使用生成器
gen = my_generator()print(next(gen))  # 输出:1
print(next(gen))  # 输出:2
print(next(gen))  # 输出:3
print(next(gen))  # 抛出 StopIteration 异常

在上面的示例中,我们定义了一个名为 my_generator 的生成器函数,它通过使用 yield 关键字来产生值。当我们调用生成器函数时,它返回一个生成器对象 gen。我们可以使用 next() 函数来逐个获取生成器的值。每次调用 next() 时,生成器函数会从上次暂停的位置继续执行,并返回 yield 语句的值。当生成器函数执行完毕或没有更多的值可生成时,调用 next() 会抛出 StopIteration 异常。

生成器的一个重要特点是它们可以节省内存,尤其在处理大量数据时非常有用。由于生成器是按需生成值,只有在需要时才会在迭代过程中生成值,不会一次性占用大量的内存。所在遍历大批量数据的时候,非常有用,因为如果将大批量的数据直接加载到内存中在遍历,肯定会消耗很多内存,而利用生成器就可以做到需要哪些遍历哪些。

如果用简单一句话来说就是,我既想大量的数据,又想让它占用空间少,实现鱼和熊掌的兼得,那么就用生成器!

def read_large_file(file_path):with open(file_path, 'r') as file:for line in file:yield line.rstrip()# 使用生成器遍历大文件
file_generator = read_large_file('large_file.txt')
print(file_generator) # 输出<generator object fibonacci_generator at 0x0000017362DCFED0>
print(type(file_generator)) # 输出<class 'generator'>
for line in file_generator:# 处理每一行数据print(line)

从上面可以看出,read_large_file() 函数是一个生成器函数,它按行从一个大文件中读取数据。通过使用 yield 关键字,在每次迭代时逐行生成文件的内容,并将其作为生成器的值返回。然后,我们可以使用 for 循环逐行处理大文件。可以看到,我们打印的file_generator类型是一个生成器。

当然,以上的例子并不一定需要采用生成器才能处理,我们直接在第4行进行处理也是可以的,生成器更多的只是提供一种思路,当你用常规方法不能解决问题的时候,可以试试用生成器。

生成器原理

生成器的原理基于迭代器(iterators)和生成器函数(generator functions)。

def even_numbers(n):for i in range(1, n+1):if i % 2 == 0:yield i# 创建生成器对象
even_generator = even_numbers(10)# 打印生成的偶数
for number in even_generator:print(number)

生成器函数

生成器通过生成器函数创建,生成器函数是一种特殊类型的函数,使用 yield 语句来生成值。像上面的例子even_numbers函数就是要给生成器函数,当调用生成器函数时,它返回一个生成器对象,而不是立即执行函数体内的代码,even_generator就是一个生成器对象。

而之前我们说过生成器是一种特殊类型的迭代器,它可以在迭代中生成值。迭代器是一个实现了 __iter__()__next__() 方法的对象。__iter__() 方法返回迭代器本身,而for循环内部会自动调用 __next__() 方法用于获取下一个值。每次调用 __next__() 方法时,生成器会从上一次暂停的位置继续执行,直到遇到下一个 yield 语句,然后将 yield 后面的值返回给调用者。

逐个生成值

生成器在调用 __next__() 方法时逐个生成值,并且每次在生成一个值后会暂停执行。这种延迟生成的机制使得生成器能够处理大量数据或无限序列,而不需要一次性加载或计算所有值。

状态保存

生成器在暂停执行时会保存其状态,包括局部变量、指令指针等信息。下一次调用 __next__() 方法时,生成器会从上一次暂停的地方恢复执行,并继续执行剩余部分的代码。

更多精彩内容,请关注同名公众:一点sir(alittle-sir)

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

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

相关文章

数据的力量:构筑现代大型网站之数据库基础与应用

目录 数据库基础知识--前言 大型网站架构特点 DBA数据库管理员 什么是数据? 数据存储 什么是数据库 数据表的概念 为什么需要mysql这样的数据库管理工具&#xff1f;★ DBMS 收费数据库与免费数据库 运维和数据库 开发与运维的不同阶段 数据库类别 数据库具体应用…

【机器学习笔记】11 支持向量机

支 持 向 量 机 &#xff08; Support Vector Machine,SVM &#xff09; 支 持 向 量 机 是 一 类 按 监 督 学 习 &#xff08; supervisedlearning&#xff09;方式对数据进行二元分类的广义线性分类器&#xff08;generalized linear classifier&#xff09;&#xff0c;其…

C#安装CommunityToolkit.Mvvm依赖

这里需要有一定C#基础&#xff0c; 首先找到右边的解决方案&#xff0c;右键依赖项 然后选择nuget管理 这里给大家扩展一下nuget的国内源&#xff08;https://nuget.cdn.azure.cn/v3/index.json&#xff09; 然后搜自己想要的依赖性&#xff0c;比如CommunityToolkit.Mvvm 再点…

Linux超详细笔记

文章目录 Linux学习笔记操作系统Linux初识Linux的诞生Linux内核Linux发行版 虚拟机VMware安装远程连接Linux系统FinalShellFinalShell连接Linux WSL配置UbuntuLinux常用命令1.入门2.ls命令cd命令3.pwd命令4.相对路径和绝对路径5.mkdir命令6.文件操作命令&#xff08;1&#xff…

vue打包优化,webpack的8大配置方案

vue-cli 生成的项目通常集成Webpack &#xff0c;在打包的时候&#xff0c;需要webpack来做一些事情。这里我们希望它可以压缩代码体积&#xff0c;提高运行效率。 文章目录 &#xff08;1&#xff09;代码压缩&#xff1a;&#xff08;2&#xff09;图片压缩&#xff1a;&…

17.3.2.9 像素处理与内存处理之比较

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请在显著位置标明本文出处以及作者网名&#xff0c;未经作者允许不得用于商业目的。 通过第17.3.2.1节到第17.3.2.8节&#xff0c;相信读者对通过锁定内存来处理图像有了一定认识。与第17.3.1节相比较&#xff0c;可以…

程序的控制结构详解

程序的控制结构 结构化程序设计方法的基础 在计算机刚出现的早期&#xff0c;它的价格昂贵、内存很小、速度慢。程序员为了在很小的内存中解决大量的科学计算问题&#xff0c;并为了节省昂贵的CPU机时费&#xff0c;不得不使用巧妙的手段和技术&#xff0c;手工编写各种高效的…

【python】网络爬虫与信息提取--正则表达式

一、正则表达式 正则表达式是用来简洁表达一组字符串的表达式。是通用的字符串表达框架&#xff0c;简洁表达一组字符串的表达式&#xff0c;针对字符串表达“简洁”和“特征”思想的工具&#xff0c;判断某字符串的特征归属。 用处&#xff1a;表达文本类型的特征&#xff1b;…

永久禁止windows自动更新方法

文章目录 前言一、打开本地组策略编辑器二、禁用windows更新总结 前言 每次打开电脑&#xff0c;右下角就会弹出设备更新提示&#xff0c;看着令人烦恼&#xff0c;并且更新可能导致电脑设置发生改变甚至是卡顿&#xff0c;所以为了自己方便于是出了禁用电脑更新的办法&#x…

对账中心系统架构设计与实现的实践总结

随着数字化时代的到来&#xff0c;越来越多的企业开始使用对账中心系统来管理其财务交易。对于一个成功的对账中心系统&#xff0c;其架构设计和实现非常关键。本文将探讨对账中心系统架构设计与实现的重要性、关键原则和实施过程中需要考虑的要点&#xff0c;帮助企业构建强大…

第13章 网络 Page747~749 asio核心类 ip::tcp::resolver

3&#xff0c; ip::tcp::resolver 如果新浪的IP地址变了&#xff0c;该怎么办呢? ip::tcp::resolver 可以帮我们用上www.sina.com.cn&#xff0c;因为它负责将人类可读的多种网址信息&#xff0c;一步 到位地解析成ip::tcp::socket建立连接所需要的ip::tcp::endpoint结构&…

C语言—函数

1.编写一个函数&#xff0c;通过输入一个数字字符&#xff0c;返回该数字29. /*1.编写一个函数&#xff0c;通过输入一个数字字符&#xff0c;返回该数字 */#include <stdio.h>//函数定义,返回类型为int int char_num(char c) {if(c > 0 && c < 9) //检查…

SQL32 截取出年龄(substring_index函数的用法)

代码 select substring_index(substring_index(profile,,,3),,,-1) as age ,count(device_id) from user_submit group by age知识点 substring_index(FIELD, sep, n)可以将字段FIELD按照sep分隔&#xff1a; (1).当n大于0时取第n个分隔符(n从1开始)之前的全部内容&#xff1…

关于umi ui图标未显示问题

使用ant design pro 时&#xff0c;安装了umi ui &#xff0c;安装命令&#xff1a; yarn add umijs/preset-ui -D但是启动项目后&#xff0c;发现没有显示umi ui的图标 找了许多解决方案&#xff0c;发现 umi的版本问题&#xff0c;由于我使用的ant design pro官网最新版本&a…

沐编程APP免费下载|获取免费项目以及技术教程

软件介绍 沐编程专注于分享IT编程相关知识的网站&#xff0c;主要分享毕业设计案例代码&#xff0c;课程设计案例代码&#xff0c;实用功能代码&#xff0c;bug解决方案&#xff0c;编程工具推荐以及编程课程分享等 下载方式 蓝奏云下载&#xff1a;https://wfr.lanzout.com…

[ai笔记9] openAI Sora技术文档引用文献汇总

欢迎来到文思源想的ai空间&#xff0c;这是技术老兵重学ai以及成长思考的第9篇分享&#xff01; 这篇笔记承接上一篇技术文档的学习&#xff0c;主要是为了做一个记录&#xff0c;记录下openai sora技术介绍文档提到的一些论文&#xff0c;再此特地记录一下&#xff01; 1 原文…

Sora 文生视频提示词实例集 2

Prompt: Historical footage of California during the gold rush. 加利福尼亚淘金热期间的历史影像。 Prompt: A close up view of a glass sphere that has a zen garden within it. There is a small dwarf in the sphere who is raking the zen garden and creating patter…

MySQL篇之SQL优化

一、表的设计优化 表的设计优化&#xff08;参考阿里开发手册《嵩山版》&#xff09;&#xff1a; 1. 比如设置合适的数值&#xff08;tinyint int bigint&#xff09;&#xff0c;要根据实际情况选择。 2. 比如设置合适的字符串类型&#xff08;char和varchar&#xff09…

pytorch 实现线性回归(深度学习)

一 查看原始函数 初始化 %matplotlib inline import random import torch from d2l import torch as d2l 1.1 生成原始数据 def synthetic_data(w, b, num_examples):x torch.normal(0, 1, (num_examples, len(w)))y torch.matmul(x, w) bprint(x:, x)print(y:, y)y tor…

阿里云ECS香港服务器性能强大、cn2高速网络租用价格表

阿里云香港服务器中国香港数据中心网络线路类型BGP多线精品&#xff0c;中国电信CN2高速网络高质量、大规格BGP带宽&#xff0c;运营商精品公网直连中国内地&#xff0c;时延更低&#xff0c;优化海外回中国内地流量的公网线路&#xff0c;可以提高国际业务访问质量。阿里云服务…