Loading [MathJax]/jax/input/TeX/jax.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >理解for循环的运行机制

理解for循环的运行机制

作者头像
老齐
发布于 2021-03-11 07:11:40
发布于 2021-03-11 07:11:40
1.4K00
代码可运行
举报
文章被收录于专栏:老齐教室老齐教室
运行总次数:0
代码可运行

注: 本文是对《Python大学实用教程》和《跟老齐学Python:轻松入门》中关于for循环内容的提升。


Python语言中,for循环非常强大,乃至于通常都不怎么提倡使用递归,所有遇到递归的时候,最好都改为for循环。对于初学者而言,for循环理解起来并不难,一般的入门读物中也都这么解释:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> lst = [0,1,2,3]
>>> for i in lst:
...     print(i)
...
0
1
2
3

变量 i依次引用列表list中的每个元素。比如我在自己的两本书《Python大学实用教程》和《跟老齐学Python:轻松入门》中,都是用这种方法对for循环进行了说明。

但是——转折了,非常重要——这种解释仅仅是就表象上向初学者做的解释,并没有揭示for循环的内在运行机制

我在《Python大学实用教程》一书中,曾以下面的方式对for循环做了深入阐述(参阅190页):

从这里我们知道,在进行 for循环的时候,其实是将被循环的对象转换为了可迭代对象——注意这个转换,非常重要。转换了之后,for循环是怎么运行的?在书中并没有深入讲解,下面我们就此给予介绍。

首先说明,本文内容的最主要参考或者说根据,就是Python语言的官方文档:https://docs.python.org/3/reference/compound_stmts.html#for,在这里对for循环语句有非常详细的说明。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
for_stmt ::=  "for" target_list "in" expression_list ":" suite
              ["else" ":" suite]

按照上述文档中的说明,对于前面的示例,将列表lst=[0,1,2,3]作为for循环语句中的expression_list,即将其转化为可迭代对象,并且只转化一次,不妨用iter_lst表示这个可迭代对象。然后就依次将这个可迭代对象的元素读入内存,并按照顺序,依次赋值给target_list。注意,不论target_list是什么,都是将所读入的可迭代对象匀速依次赋值。

用上面循环语句示例理解这段话,其分解动作如下:

  1. lst=[0,1,2,3]转换为可迭代对象,暂记作iter_lst
  2. 读入iter_lst的第一个元素0,并将它赋值给i(这里的i就对应着上面语法规则中的target_list
    1. 于是有:i=0
    2. pirnt(i),就打印出了0
  3. 读入iter_lst的第二个元素1,并将它赋值给i
    1. 于是有:i=1
    2. print(i),就打印出了1

,按照上面的过程不断重复,直到最后一个元素`4`为止——因为`for`循环语句能够自动捕获迭代到最后一个元素之后的异常,所以,`for`循环能够在到达最后一个元素之后,结束循环。$$

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> iter_lst=iter(lst)

用内置函数iter(),依据列表lst创建了一个可迭代对象iter_lst

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> iter_lst=iter(lst)
>>> i = next(iter_lst)
>>> print(i)
0

这就完成了第一个循环。然后依次方式,向下循环:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# 第二个循环
>>> i = next(iter_lst)
>>> print(i)
1
# 第三个循环
>>> i = next(iter_lst)
>>> print(i)
2
# 第四个循环
>>> i = next(iter_lst)
>>> print(i)
3
# 到最后一个元素后面,抛出异常
>>> i = next(iter_lst)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

上面的演示,如果连贯起来,就是for循环——貌似没有什么奇怪的。

下面就要见证奇迹了。

经过上述操作之后,列表lst并没有发生变化——好像是废话。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> lst
[0, 1, 2, 3]

勿要着急,伟大总是孕育在平凡之中。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> iter_lst=iter(lst)
>>> i = next(iter_lst)
>>> print(i)
0
>>> lst
[0, 1, 2, 3]

完成第一循环,跟前面一样,并且在此时,查看了一下列表lst,没有变化。但是,我在这里做一个操作:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> lst[1]=111
>>> lst
[0, 111, 2, 3]

此时,将列表中序号为1的元素值修改为111,即lst[1]=111。如果按照读取可迭代对象的顺序,按照原来的流程,是要读取第二个元素1了,但是,在读取之间,我将列表中的第二个元素修改为111,那么,如果再进行下面的操作:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> i = next(iter_lst)

读取了可迭代对象的第二个元素,并把它赋值给变量i,此时,它是1还是111呢?

看结果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> print(i)
111

不是1,而是111。再详细循环,就跟前述过程一样了。

这说明,如果将列表lst转换为可迭代对象之后,这个可迭代对象中的元素是对lst中元素的引用,并不是在可迭代对象中建立一套新的对象。

理解了上面的道理,看下面的操作,是不是能够解释?

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> a = ['python', 'java', 'c', 'rust']
>>> iter_a = iter(a)
>>> a[1] = next(iter_a)
>>> a
['python', 'python', 'c', 'rust']

关键的一句是a[1] = next(iter_a)next(iter_a)得到了迭代器对象的第一个元素'python',并且将它赋值给a[1],这样,列表a中的索引是1的元素就变成了'python',即原来的'java'被替换为'python'了。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> a[1] = next(iter_a)
>>> a
['python', 'python', 'c', 'rust']

继续读取可迭代对象的第二个元素'python'

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> a[1] = next(iter_a)
>>> a
['python', 'c', 'c', 'rust']

继续读取可迭代对象的第三个元素'c',在赋值给a[1],也就是列表a中的索引是1的元素变成了'c'

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> a[1] = next(iter_a)
>>> a
['python', 'rust', 'c', 'rust']

这次a[1]='rust',根据前面的说明,应该容易理解了。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> a[1] = next(iter_a)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

最后报异常了。如果将上述过程,写成for循环,是这样的:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> a = ['python', 'java', 'c', 'rust']
>>> for a[1] in a:
...     print(a, a[1])
...
(['python', 'python', 'c', 'rust'], 'python')
(['python', 'python', 'c', 'rust'], 'python')
(['python', 'c', 'c', 'rust'], 'c')
(['python', 'rust', 'c', 'rust'], 'rust')

上面循环语句中的a[1]就如同前面演示的i那样,都是循环语法结构中的target_list,只不过这里出了要完成赋值之外,还要同时实现对列表a中索引是1的元素修改,即实现上面分解动作中a[1] = next(iter_a)

似乎这里使用a[1]有点怪异。的确,在通常操作中很少这么做的。不过,上面的做法,倒是能让我们对for循环有了深刻理解。

理解了本文所介绍的内容,就不难回答stackoverflow上的一个问题了(https://stackoverflow.com/questions/55644201/why-can-i-use-a-list-index-as-an-indexing-variable-in-a-for-loop):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> b = [0,1,2,3]
>>> for b[-1] in b:
...     print(b[-1])
...
0
1
2
2

是否能自己解释这个结果?

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-02-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 老齐教室 微信公众号,前往查看

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

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

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
jq---方法总结
1. 什么是jQuery 在使用jQuery之前,我们必须先了解什么是jQuery,它能够干什么(不然我们为啥要用它)。 jQuery是一个非常流行的快速、小巧、功能强大的开源JavaScript库。就像官方所宣称的那样——"Write less,do more",它使得我们常用的HTML文档遍历、DOM操作、事件处理、动画效果、Ajax、工具方法等功能代码的实现变得非常简单。更重要的是,它还为我们做了跨浏览器的兼容。绝大多数时候,妈妈再也不用担心我的JS兼容问题了(由于浏览器bug等因素,jQuery也无
小蔚
2019/09/11
3.2K0
jquery第一次课的案例教程
js库:把一些常用到的方法写到一个单独的js文件,使用的时候直接去引用这js文件就可以了。 (animate.js、common.js)
张哥编程
2024/12/19
2130
JQuery快速入门
Write less, do more, I like jQuery. jQuery是最常用的js库,整体来说非常轻量并易于扩展,对于移动应用可以使用其更轻量的孪生兄弟Zepto代替。其是由John
用户1216676
2018/01/24
2.7K0
JQuery快速入门
JavaWeb(八)JQuery
jQuery 市场用得比较多两个框架: jQuery 比较适合做一些互联网 的应用(12306.com,蘑菇街,美丽说,聚美) extjs 比较适合做后台管理系统(电商(订单管理),银行,电信) 核心: 主要功能:javascript开发人员查找元素、操作DOM、处理事件、执行动画和开发Ajax的操作。优势:(宗旨:write less ,do more 写更少的代码,做更多的事情) 1:轻量级 (js 库非常小) 2:强大的选择器(获取页面上面的dom 元素 document.getElementByI
二十三年蝉
2018/02/28
1.9K0
jquery入门
运用jQuery时,需要在页面中引入jQuery文件 jQuery的hello world <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>helloworld</title> <!-- 1. 在页面中引入jQuery支持 --> <script src="js/jquery-1.12
周小董
2019/03/25
3K0
jQuery笔记(1) (多图)
即library,是一个封装好的特定的集合(方法和函数).从封装一大堆函数的角度理解库,就是在这个库中,封装了很多预先定义好的函数在里面,比如animate,hide,show,比如获取元素等/
y191024
2022/09/20
9.2K0
jQuery笔记(1) (多图)
「jQuery」基础 - 01
请注意,本文编写于 2075 天前,最后修改于 173 天前,其中某些信息可能已经过时。
曼亚灿
2023/05/17
7.1K0
「jQuery」基础 - 01
Web阶段:第五章:JQuery库
点击:API文档下载 Jquery介绍 1.什么是JQuery ? jQuery,顾名思义,也就是JavaScript和查询(Query),它就是辅助JavaScript开发的js类库。 2.JQue
Java廖志伟
2022/09/28
26.7K0
Web阶段:第五章:JQuery库
01-老马jQuery教程-jQuery入口函数及选择器
前言 这套jQuery教程是老马专门为寒门子弟而录制,希望大家看到后能转发给更多的寒门子弟。视频都是免费,请参考课程地址:https://chuanke.baidu.com/s5508922.html
老马
2017/12/20
2.5K0
jQuery
onload 事件是等页面文档、外部的 js 文件、css文件、图片加载完毕才执行内部代码。
小丞同学
2021/08/16
8.8K0
jQuery 教程
菜鸟教程 — jQuery 教程:https://www.runoob.com/jquery/jquery-tutorial.html
全栈程序员站长
2022/09/03
17.6K0
jQuery 教程
Python全栈之jQuery笔记
jQuery runnoob网址: http://www.runoob.com/jquery/jquery-tutorial.html jQuery API手册: http://www.runoob.com/manual/jquery/ jQuery笔记 笔记来源于: 传智播客的黑马程序员视频笔记. 菜鸟教程:http://www.runoob.com/ 自己的查询与整理. JS的不完美地方: 1. 代码比较麻烦,给多个元素添加事件需要遍历,可能还需要进行嵌套.
py3study
2020/01/19
5.6K0
前端成神之路-01_jQuery
​ JavaScript库:即 library,是一个封装好的特定的集合(方法和函数)。从封装一大堆函数的角度理解库,就是在这个库中,封装了很多预先定义好的函数在里面,比如动画animate、hide、show,比如获取元素等。
海仔
2021/01/13
12.2K0
一个小时学会jQuery
前一段时间录了一套关于jQuery的视频分享给大家,可以在下载区下载到,本来想配合文字一起的,后面发现视频+帮助文档也是非常好的学习方法。 一、jQuery简介与第一个jQuery程序 1.1、jQu
张果
2018/01/04
19.1K0
一个小时学会jQuery
[Java面试九]脚本语言知识总结.
核心内容概述 1.JavaScript加强,涉及到ECMAScript语法、BOM对象、DOM对象以及事件。 2.Ajax传统编程。 3.jQuery框架,九种选择器为核心学习内容 4.JQuery UI插件 5.jQuery Ajax编程 6.jQuery第三方插件 7.反向Ajax编程(彗星) 一、JavaScript基础加强 JavaScript是在浏览器内容运行,无需编译、解释执行动态脚本语言,是一种弱类型语言,所有变量使用var定义。 JavaScript的3个组成部分分别为:核心(ECMAScr
一枝花算不算浪漫
2018/05/18
5.3K0
JQuery 学了不亏
jQuery是JavaScript的工具库,对原生JavaScript中的DOM操作、事件处理、包括数据处理和Ajax技术等进行封装,提供更完善,更便捷的方法。
杨丝儿
2022/02/24
1.9K0
JQuery 学了不亏
前端架构师之01_JQuery
常见的JavaScript类库:jQuery、Prototype、ExtJS、Mootools和YUI等。
张哥编程
2024/12/13
5090
前端之jQuery
jQuery对象就是通过jQuery包装DOM对象后产生的对象。jQuery对象是 jQuery独有的。如果一个对象是 jQuery对象,那么它就可以使用jQuery里的方法:例如$(“#i1”).html()。
GH
2019/12/16
5.1K0
jQuery基础系列
jquery的入口函数是在html所有标签都加载后才执行,而JavaScript的window.onload事件是等到所有内容加载完后才执行。
达达前端
2019/07/03
2.7K0
jQuery基础系列
jquery学习
<1> jQuery由美国人John Resig创建,至今已吸引了来自世界各地的众多 javascript高手加入其team。
菲宇
2019/06/13
2.3K0
相关推荐
jq---方法总结
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验