前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >python的for循环是什么循环_while循环的用法举例

python的for循环是什么循环_while循环的用法举例

作者头像
全栈程序员站长
发布于 2022-09-22 11:19:54
发布于 2022-09-22 11:19:54
2.4K0
举报

大家好,又见面了,我是你们的朋友全栈君。

在本篇博客中,我们将讨论 Python 中 for 循环的原理。

我们将从一组基本例子和它的语法开始,还将讨论与 for 循环关联的 else 代码块的用处。

然后我们将介绍迭代对象、迭代器和迭代器协议,还会学习如何创建自己的迭代对象和迭代器。

之后,我们将讨论如何使用迭代对象和迭代器实现 for 循环,以及利用 while 循环通过迭代器协议实现 for 循环逻辑。

最后,我们将反编译一个简单的 for 循环,并逐步介绍 Python 解释器在执行 for 循环时执行的指令,以满足大家的好奇心。这些有助于理解 for 循环运行时的内部工作原理。

Python的for循环

for 语句是 Python 中执行迭代的两个语句之一,另一个语句是 while。如果你对 Python 的迭代并不是很熟悉的话,Python中的迭代:for、while、break、以及continue语句是一个不错的切入点。

Python 中,for 循环用于遍历一个迭代对象的所有元素。循环内的语句段会针对迭代对象的每一个元素项目都执行一次。暂且可以将迭代对象想象成一个对象集合,我们可以一个个遍历里面的元素。我们将在下一节对迭代器和迭代对象作详细说明。

一个简单的 for 循环

我们先从一个简单 for 循环开始,它遍历一个字符串列表并打印每一个字符串。

如你所见,这个循环实际上遍历了列表中的每一个单词并打印它们。也就是说,在循环的每一次遍历中,变量 <i>word</i> 都被指定为列表中的一个元素,然后执行 for 语句中的代码块。由于列表是一个有序的元素序列,所以循环也是以相同的顺序遍历这些元素。

带有 else 子句的 for 循环

Python 中的 for 循环可以选择是否关联一个 else 子句。else 子句中的代码块是在 for 循环完成后才开始执行的,即在迭代对象中的所有元素都遍历完毕之后。现在我们看一下如何扩展前面的示例以包含一个 else 条件(子句)。

else 子句适用于何时?

你已经注意到,else 子句是在 for 循环完成之后才执行的。那么 else 代码块的意义是什么呢?for 循环之后的语句不是也是同样会执行吗?

我们很多时候会遇到这样一种情况,当满足某种条件时,中途结束 for 循环。且如果这个条件一直未满足,则希望执行另一组语句。我们通常使用布尔类型的标记实现,下面是一个例子。

调用结果:

而用 else 代码块的话,我们可以避免使用布尔类型的标记found_item。我们看看如何使用 else 子句重写上面的方法。注意如果 for 循环中的 break 语句被触发执行,那么则会跳过 else 块。

所以 else 代码块适用于 for 循环中有 break 语句的情况,且我们希望 break 条件没有被触发的时候执行一些语句。

否则,与 else 关联的语句只会在 for 循环结束时才执行。本文的最后一节查看反编译的字节码时你会看到这一点。

for 循环语法

我们已经看到了一些简单的例子,接下来以 for 循环的语法结束本节。

基本上,对于 iterable 中的每一个元素,都会执行 set_of_statements_1。一旦所有的元素都迭代一遍,控制器将跳转到 else 代码块中执行 set_of_statements_2。

注意,else 子句是可选的。如果没有发现 else 子句,循环会在所有元素都遍历完成后结束,并且控制器会转向程序之后的语句。

可迭代对象与迭代器

可迭代对象

在上一节,我们使用术语 iterable 来表示循环中被迭代的对象。现在我们来试着了解一下 Python 中的 iterable 对象是什么。

Python 中,一个 iterable 对象指在 for 循环中可以被迭代的任意对象。这意味着,当这个对象作为参数传递给 iter()方法时应该返回一个迭代器。我们来看一下 Python 中的一些常用的内置迭代的例子。

如你所见,当我们对一个 iterable 对象调用 iter() 时,它会返回一个迭代器对象。

迭代器

那么什么是迭代器呢?迭代器在 Python 中被定义为一个表现为流式数据的对象。基本上,如果我们将对象传递给内置的next() 方法,它应该从与之关联的流式数据中返回下一个值。一旦所有的元素都遍历结束,它会抛出一个*StopIteration* 异常。next()方法的后续调用也都会抛出*StopIteration* 异常。

我们用一个列表来试一下。

迭代器也是可迭代对象!但是…

有一个很有趣的事需要记一下,迭代器同样支持(强制要求支持迭代器协议iter() 方法。这意味着我们可以对一个迭代器调用iter() 方法并获取它自身的迭代器对象。

因此,我们可以在任何期望使用迭代器的地方使用它。比如,for 循环。

然而要注意一点,在像 list 这样的容器对象上调用 iter() 每次都会返回不同的迭代器,而在迭代器上调用 iter() 仅仅返回同一个迭代器。

所以如果你需要进行多次迭代,并且用迭代器替换普通容器或可迭代对象,那么第二次你会看到一个空的容器。

对一个列表迭代两次

请注意,这是按照我们的期望运行的。

对一个列表迭代器迭代两次

请注意,迭代器在第一次循环的时候就已经结束了,第二次我们看到的是一个空容器。

迭代器协议

前文我们看到了:

1. 一个可迭代对象,作为参数传递给 iter() 方法时返回一个迭代器。

2. 一个迭代器,

1. 作为参数传递给next()方法时返回它的下一个元素或者在所有元素都遍历结束时抛 出StopIteration 异常。

2. 作为参数传递给iter() 方法时返回它自身。

迭代协议仅仅只是一种将对象定义为迭代器的标准方式。我们已经在前一节看到了这种协议的实际应用。根据协议,迭代器应该定义以下两个方法:

1. __next__()

1. 每次调用这个方法时,应该返回迭代器的下一个元素。一旦元素都遍历结束,它应该抛出StopIteration 异常。

2. 当我们调动内置函数next() 时,实际内部调用的是本方法。

2. __iter__()

1. 这个方法返回迭代器自身

2. 当我们调动内置函数iter() 时,实际内部调用的是本方法。

自己写一个迭代器

现在我们已经知道迭代协议的原理,可以写一个自己的迭代器了。我们先看一个例子,下面我们创建了一个根据给定范围和步长的 Range 类。

我们看一下它在 for 循环中是怎么工作的。

注意,Range 类的实例是迭代器也是可迭代对象。

自己写一个可迭代对象

我们还可以基于 Range 迭代器另外创建一个可迭代对象。它的作用是每当调用 __iter()__ 方法是返回一个新的迭代器,在这里,它应该返回一个新的 Range 对象。

在 for 循环中使用我们这个 RangeIterable。

for 循环工作原理

现在我们已经知道什么是迭代器和可迭代对象,接下来了解一下 for 循环是如何工作的。

再看一下前面的例子。

当我们执行上面的代码块时,发生了以下这些事情:

1. 在 for 语句内部对列表 [“You”, “are”, “awesome!”] 调用了 iter() 方法,返回结果是一个迭代器。

2. 然后对迭代器调用 next() 方法,并将其返回值赋给变量 word。

3. 之后,会执行 for 循环中关联的语句块。这个例子中是打印 word。

4. 在 next() 方法抛出 StopIteration 之前会一直重复执行第 2,3 步。

5. 一旦 next() 抛出 StopIteration,控制器会跳转到 else 子句(如果存在)并执行与 else 关联的语句块。

注意:如果在步骤 3 中,for 循环语句遇到了 break 语句,则跳过 else 代码块。

使用 while 语句实现 for 循环逻辑

我们可以像下面这样使用 while 语句实现之前的逻辑。

while 循环的行为实际上与 for 循环相同,上面的代码会有以下输出。

反编译 for 循环

在本节,我们将反编译 for 循环并逐步说明解释器在执行 for 循环时的指令。这里使用dis 模块来反编译 for 循环。详细来说,就是我们将使用 dis.dis 方法来生成可读性更高的字节码。

我们会使用之前一直用的简单 for 循环示例。接下来将文件写入文件 for_loop.py。

我们可以调用 dis.dis 方法获得可读性高的字节码。在终端上运行以下命令。

更多Python视频、资料、代码加群531509025免费获取

反编译输出的每列表示以下内容:

1. 第 1 列:代码行数。

2. 第 2 列:如果是跳转指令,则有 “>>” 符号。

3. 第 3 列:以字节为单位的字节码偏移量。

4. 第 4 列:字节码指令本身。

5. 第 5 列:展示指令的参数。如果括号中有内容,它只是对参数做了更好的可读性转化。

现在我们来一步步浏览反编译后的字节码,并尝试了解实际发生了什么。

1. 第 1 行,即,”for word in [“You”, “are”, “awesome!”]:” 转译为:

0 SETUP_LOOP 28 (to 30)

该语句将 for 循环中的代码块推送到栈中。这段代码块会跨越 28 个字节,达到 “30”。

这意味着,如果 for 循环中有 break 语句,那么控制器将跳转到偏移位置 “30”。注意当遇到 break 语句时是如何跳过 else 代码块的。

2 LOAD_CONST 0 ((‘You’, ‘are’, ‘awesome!’))

接下来,列表被推送到栈顶(TOS,之后使用 TOS 表示栈顶或栈顶元素)。

4 GET_ITER

该指令实现 “TOS = iter(TOS)”。这表示从列表获取一个迭代器(当前为 TOS),然后将迭代器推送给 TOS。

6 FOR_ITER 12 (to 20)

该指令获取 TOS,作为当前的迭代器, 并调用 next() 方法。

如果 next() 方法产生一个值,则将其作为 TOS 推送到栈,并执行吓一跳指令 “8 STORE_NAME”。

一旦 next() 表明迭代器已经遍历结束(即抛出 StopIteration 异常),TOS(迭代器)将从栈中弹出,字节码计数器会增加 12。这表示控制器跳转到指令 “20 POP_BLOCK”。

8 STORE_NAME 0 (word)

这个指令执行了转换 word = TOS,即,next()返回的值被赋给变量word

2. 第 1 行,即,“print(word)” 转译为:

10 LOAD_NAME 1 (print)

将可调用方法print 推送到栈中。

12 LOAD_NAME 0 (word)

将栈中的word作为参数推送给print

14 CALL_FUNCTION 1

调用带位置参数的函数。

像我们看到的指令那样,与函数关联的参数会出现在 TOS 中。在获得可调用象的对(如print)之前,会弹出所有遇到的参数。

一旦获得可调用对象,则把所有参数传递给它并调用。

可调用对象执行结束后,把返回值推送到 TOS 中,这里是 None。

16 POP_TOP

TOS(栈顶元素),即将函数的返回值从栈中移除(弹出)。

18 JUMP_ABSOLUTE 6

此时字节码计数器为 “6”,这表示下一条指令将执行 “6 FOR_ITER”。这是循环遍历迭代器中元素的方式。

注意,一旦迭代器中的元素都遍历结束,指令 “6 FOR_ITER” 会结束循环并跳转到 “20 POP_BLOCK”。

20 POP_BLOCK

POP_BLOCK 会从代码块的栈中移除由 “0 SETUP_LOOP” 设置的代码块。

3. 注意第 3 行(对应else),没有关联任何特殊指令。程序控制器会顺序执行下一条与else 相关的指令。

4. 第 4 行,即,“print(“See you later!“)” 转译为:

22 LOAD_NAME 1 (print)

推送与print 相关的可调用方法到栈中。

24 LOAD_CONST 1 (‘See you later!‘)

推送可调用函数的参数对象到栈中。

26 CALL_FUNCTION 1

可调用函数及其参数会从栈中弹出,然后执行函数并将其返回值推送到 TOS。

28 POP_TOP

TOS(栈顶元素),即将函数返回值(这里是 None)从栈中移除。

5. 下面的两个指令只是简单的将脚本的返回值(None)加载到栈并返回。

30 LOAD_CONST 2 (None)

32 RETURN_VALUE

喔!现在我们已经了解了 for 循环反编译后的指令。希望这有助于更好地理解 for 循环的工作原理。

结尾给大家推荐一个非常好的学习教程,希望对你学习Python有帮助!

基础入门教程推荐:更多Python视频教程-关注B站:Python学习者 https://player.bilibili.com/player.html?aid=847801620

【Python教程】全网最容易听懂的1000集python系统学习教程(答疑在最后四期,满满干货)

爬虫案例教程推荐:更多Python视频教程-关注B站:Python学习者 https://player.bilibili.com/player.html?aid=372208936

2021年Python最新最全100个爬虫完整案例教程,数据分析数据可视化,记得收藏哦

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/170040.html原文链接:https://javaforall.cn

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
转转平台IM系统架构设计与实践(一):整体架构设计
转转是二手电商平台,在这个平台上,人人可以是买家,人人也可以是卖家。转转从最初的信息模式升级为一个闭环的交易模式,IM打通了买家与卖家之间的通道。本文描述了转转IM为整个平台提供的支撑能力,给出了系统的整体架构设计,分析了系统架构的特性。
JackJiang
2025/01/09
1010
转转平台IM系统架构设计与实践(一):整体架构设计
跟着源码学IM(十一):一套基于Netty的分布式高可用IM详细设计与实现(有源码)
本文将要分享的是如何从零实现一套基于Netty框架的分布式高可用IM系统,它将支持长连接网关管理、单聊、群聊、聊天记录查询、离线消息存储、消息推送、心跳、分布式唯一ID、红包、消息同步等功能,并且还支持集群部署。
JackJiang
2023/06/09
1.3K0
跟着源码学IM(十一):一套基于Netty的分布式高可用IM详细设计与实现(有源码)
支持百万人超大群聊的Web端IM架构设计与实践
现在IM群聊产品多种多样,有国民级的微信、QQ,企业级的钉钉、飞书,还有许多公司内部的IM工具,这些都是以客户端为主要载体。而且群聊人数通常都是有限制,微信正常群人数上限是500,QQ2000人,收费能达到3000人,这里固然有产品考量,但技术成本、资源成本也是很大的因素。笔者的业务场景上正好需要一个迭代更新快、轻量级(不依赖客户端)、单群百万群成员的纯H5的IM产品。
JackJiang
2025/03/13
1220
支持百万人超大群聊的Web端IM架构设计与实践
B站千万级长连接实时消息系统的架构设计与实践
用户通过发送弹幕、送礼等,可以实时在直播画面上展现自己的想法、评论和互动内容,从而丰富了用户观看体验。在这个过程中,实时向终端推送互动信息,就需要用到长连接。
JackJiang
2024/05/16
4260
B站千万级长连接实时消息系统的架构设计与实践
《基于实践,设计一个百万级别的高可用 & 高可靠的 IM 消息系统》
https://xie.infoq.cn/article/4061081a5ce66137a8c021994
后台技术汇
2022/05/28
2K0
《基于实践,设计一个百万级别的高可用 & 高可靠的 IM 消息系统》
基于实践:一套百万消息量小规模IM系统技术要点总结
本文由公众号“后台技术汇”分享,原题“基于实践,设计一个百万级别的高可用 & 高可靠的 IM 消息系统”,原文链接在文末。由于原文存在较多错误和不准确内容,有大量修订和改动。
JackJiang
2021/11/27
2.2K0
基于实践:一套百万消息量小规模IM系统技术要点总结
IM开发快速入门(一):什么是IM系统?
本文在编写时参考了博客作者“鹿呦呦”和在线课程“即时消息技术剖析与实战”的相关资料,一并表示感谢。
JackJiang
2020/07/09
2.7K0
一个海量在线用户即时通讯系统(IM)的完整设计
移动端重点是移动端,支持IOS/Android系统,包括IM App,嵌入消息功能的瓜子App,未来还可能接入客服系统。
普通程序员
2019/10/23
3.2K0
一个海量在线用户即时通讯系统(IM)的完整设计
一个海量在线用户即时通讯系统(IM)的完整设计Plus
《一个海量在线用户即时通讯系统(IM)的完整设计》(以下称《完整设计》)这篇文章发出来之后有不少读者咨询问题,提出意见或建议。主要集中在模块拆分、协议、存储等方面。针对这些问题做个简单说明。
Criss@陈磊
2019/08/02
5.8K0
教你微信IM即时消息系统的架构设计
用户收发消息的终端,内置的客户端程序和服务端进行网络通信,用来承载用户的互动请求和消息接收功能。
JavaEdge
2021/02/23
2.2K0
全栈必备:系统架构设计的10个思维实验
软件系统的架构设计经验很难获得。即便工作多年,能够完成系统架构设计的机会也很有限。如何提高自己的系统架构设计能力呢?不断实践当然不可或缺,思维实验或许也是一种有效的方式。
半吊子全栈工匠
2023/09/02
3490
全栈必备:系统架构设计的10个思维实验
一套分布式IM即时通讯系统的技术选型和架构设计
针对聊天本身来说,最核心的需求就是:发送文字、图片、文件、语音、视频、消息缓存、消息存储、消息未读、已读、撤回,离线消息、历史消息、单聊、群聊,多端同步,以及其他一些需求。
JackJiang
2023/12/21
2.5K0
一套分布式IM即时通讯系统的技术选型和架构设计
直播系统聊天技术(四):百度直播的海量用户实时消息系统架构演进实践
本文原题“百度直播消息服务架构实践”,由百度APP消息中台团队原创分享于“百度Geek说”公众号,为了让文章内容更通俗易懂,本次已做排版优化和内容重新划分,原文链接在文末。
JackJiang
2021/04/27
1.3K0
快给你的软件加IM聊天功能!
大部分IM为便于查看历史消息或暂存离线消息,都需对消息进行服务端存储,那怎么存储或暂存。
JavaEdge
2021/02/23
1.7K0
快给你的软件加IM聊天功能!
58同城高性能移动Push推送平台架构演进之路
关于作者:孙玄,58赶集集团系统架构师,技术负责人,技术委员会架构组主任,也是58同城即时通讯、C2C技术负责人,负责58核心系统的架构以及优化工作。分布式系统存储专家,前百度高级工程师,参与社区搜索部多个基础系统的设计与实现。
后端技术探索
2018/08/09
2K0
一套亿级用户的IM架构技术干货(下篇):可靠性、有序性、弱网优化等
本文内容和编写思路是基于邓昀泽的“大规模并发IM服务架构设计”、“IM的弱网场景优化”两文的提纲进行的,感谢邓昀泽的无私分享。
JackJiang
2021/03/22
7280
vivo手机上的系统级消息推送平台的架构设计实践
本文内容来自vivo互联网服务器团队李青鑫在“2021 vivo开发者大会”现场的演讲内容整理而成(现场演讲稿可从本文末附件中下载)。
JackJiang
2022/08/09
1.5K0
vivo手机上的系统级消息推送平台的架构设计实践
听说你会架构设计?来,弄一个群聊系统
大家好,我是小❤,一个漂泊江湖多年的 985 非科班程序员,曾混迹于国企、互联网大厂和创业公司的后台开发攻城狮。
xin猿意码
2023/11/08
5950
听说你会架构设计?来,弄一个群聊系统
【架构设计】高并发IM系统架构优化实践
作者简介: 少强,网名无衣蒹葭,阿里云资深工程师,主要做分布式存储和搜索相关的工作。 摘要: 介绍如何设计一个稳定、高并发、消息保序的IM系统,以及如何通过使用存储层的高级功能来优化系统架构。 在构建社交IM和朋友圈应用时,一个基本的需求是将用户发送的消息和朋友圈更新及时准确的更新给该用户的好友。为了做到这一点,通常需要为用户发送的每一条消息或者朋友圈更新设置一个序号或者ID,并且保证递增,通过这一机制来确保所有的消息能够按照完整并且以正确的顺序被接收端处理。当消息总量或者消息发送的并发数很大的时候,我们通
数据和云
2018/03/07
2.2K0
【架构设计】高并发IM系统架构优化实践
零基础IM开发入门(三):什么是IM系统的可靠性?
本文编写时引用了“聊聊IM系统的即时性和可靠性”一文的部分内容和图片,感谢原作者。
JackJiang
2020/10/29
9180
推荐阅读
相关推荐
转转平台IM系统架构设计与实践(一):整体架构设计
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档