详解Python中for循环是如何工作的


Posted in Python onJune 30, 2017

前言

for...in 是Python程序员使用最多的语句,for 循环用于迭代容器对象中的元素,这些对象可以是列表、元组、字典、集合、文件,甚至可以是自定义类或者函数,例如:

作用于列表

>>> for elem in [1,2,3]:
...  print(elem)
...
1
2
3

作用于元组

>>> for i in ("zhang", "san", 30):
...  print(i)
...
zhang
san
30

作用于字符串

>>> for c in "abc":
...  print(c)
...
a
b
c

作用于集合

>>> for i in {"a","b","c"}:
...  print(i)
...
b
a
c

作用于字典

>>> for k in {"age":10, "name":"wang"}:
...  print(k)
...
age
name

作用于文件

>>> for line in open("requirement.txt"):
...  print(line, end="")
...
Fabric==1.12.0
Markdown==2.6.7

可能有人不经要问,为什么这么多不同类型对象都支持 for 语句,还有哪些类型的对象可以作用在 for 语句中呢?回答这个问题之前,我们先要了解 for 循环背后的执行原理。

for 循环是对容器进行迭代的过程,什么是迭代?迭代就是从某个容器对象中逐个地读取元素,直到容器中没有更多元素为止。那么,哪些对象支持迭代操作?任何对象都可以吗?先随便自定义一个类试试,看行不行:

>>> class MyRange:
...  def __init__(self, num):
...   self.num = num
...
>>> for i in MyRange(10):
...  print(i)
...
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
TypeError: 'MyRange' object is not iterable

错误堆栈日志非常清楚地告诉我们,MyRange 不是一个可迭代对象,所以它不能用于迭代,那么到底什么样的对象才称得上是可迭代对象(iterable)呢?

可迭代对象需要实现__iter__方法,并返回一个迭代器,什么是迭代器呢?迭代器只需要实现 __next__方法。现在我们就来验证一下列表为什么支持迭代:

>>> x = [1,2,3]
>>> its = x.__iter__() # x有此方法,说明列表是可迭代对象
>>> its
<list_iterator object at 0x100f32198>

>>> its.__next__() # its有此方法,说明its是迭代器
1
>>> its.__next__()
2
>>> its.__next__()
3
>>> its.__next__()
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
StopIteration

从试验结果来看,列表是一个可迭代对象,因为它实现了 __iter__方法,并且返回了一个迭代器对象(list_iterator),因为它实现了 __next__方法。我们看到它不断地调用__next__方法,其实就是不断地迭代获取容器中的元素,直到容器中没有更多元素抛出 StopIteration 异常为止。

那么 for 语句又是如何循环的呢?到这里,恐怕你也猜到了,它的步骤是:

  • 先判断对象是否为可迭代对象,不是的话直接报错,抛出TypeError异常,是的话,调用 __iter__方法,返回一个迭代器
  • 不断地调用迭代器的__next__方法,每次按序返回迭代器中的一个值
  • 迭代到最后,没有更多元素了,就抛出异常 StopIteration,这个异常 python 自己会处理,不会暴露给开发者

详解Python中for循环是如何工作的

对于元组,字典,字符串也是同样的道理,弄明白了 for 的执行原理之后,我们就可以实现自己的迭代器用在 for 循环中。

前面的 MyRange 报错是因为它没有实现迭代器协议里面的这两个方法,现在继续改进:

class MyRange:
 def __init__(self, num):
  self.i = 0
  self.num = num

 def __iter__(self):
  return self

 def __next__(self):
  if self.i < self.num:
   i = self.i
   self.i += 1
   return i
  else:
   # 达到某个条件时必须抛出此异常,否则会无止境地迭代下去
   raise StopIteration()

因为它实现了__next__方法,所以 MyRange 本身已经是一个迭代器了,所以 __iter__返回的就是对象本身 self。现在用在 for 循环中试试:

for i in MyRange(3):
 print(i)
# 输出
 0
 1
 2

有没有发现,自定义的 MyRange 功能和内建函数 range很相似。for 循环本质是不断地调用迭代器的__next__方法,直到有 StopIteration 异常为止,所以任何可迭代对象都可以作用在for循环中。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

Python 相关文章推荐
Python和Ruby中each循环引用变量问题(一个隐秘BUG?)
Jun 04 Python
python中使用urllib2获取http请求状态码的代码例子
Jul 07 Python
Python使用email模块对邮件进行编码和解码的实例教程
Jul 01 Python
python中requests爬去网页内容出现乱码问题解决方法介绍
Oct 25 Python
Python解决抛小球问题 求小球下落经历的距离之和示例
Feb 01 Python
使用apidocJs快速生成在线文档的实例讲解
Feb 07 Python
Ubuntu16.04/树莓派Python3+opencv配置教程(分享)
Apr 02 Python
django中静态文件配置static的方法
May 20 Python
Python全局变量与局部变量区别及用法分析
Sep 03 Python
Python读写操作csv和excle文件代码实例
Mar 16 Python
Numpy 理解ndarray对象的示例代码
Apr 03 Python
基于Python绘制子图及子图刻度的变换等的问题
May 23 Python
python 连接sqlite及简单操作
Jun 30 #Python
利用Python破解斗地主残局详解
Jun 30 #Python
Python实现的文本编辑器功能示例
Jun 30 #Python
Python构建XML树结构的方法示例
Jun 30 #Python
基于python的Tkinter编写登陆注册界面
Jun 30 #Python
Python使用微信SDK实现的微信支付功能示例
Jun 30 #Python
python实现的二叉树定义与遍历算法实例
Jun 30 #Python
You might like
PHP 中dirname(_file_)讲解
2007/03/18 PHP
基于Zookeeper的使用详解
2013/05/02 PHP
php 注册时输入信息验证器的实现详解
2013/07/05 PHP
js获取视频时长代码
2014/04/10 Javascript
javascript实现图片循环渐显播放的方法
2015/02/24 Javascript
原生JavaScript编写俄罗斯方块
2015/03/30 Javascript
JQuery鼠标移到小图显示大图效果的方法
2015/06/10 Javascript
jQuery基于ajax实现带动画效果无刷新柱状图投票代码
2015/08/10 Javascript
javascript 动态修改css样式方法汇总(四种方法)
2015/08/27 Javascript
jQuery实现分章节锚点“回到顶部”动画特效代码
2015/10/23 Javascript
js实现文件上传表单域美化特效
2015/11/02 Javascript
简单介绍JavaScript数据类型之隐式类型转换
2015/12/28 Javascript
悬浮广告方法日常收集整理
2016/03/18 Javascript
jquery实现无刷新验证码的简单实例
2016/05/19 Javascript
关于JS中setTimeout()无法调用带参函数问题的解决方法
2016/06/21 Javascript
打造自己的jQuery插件入门教程
2016/09/23 Javascript
微信小程序 触控事件详细介绍
2016/10/17 Javascript
使用clipboard.js实现复制功能的示例代码
2017/10/16 Javascript
jQuery创建及操作xml格式数据示例
2018/05/26 jQuery
vue + typescript + 极验登录验证的实现方法
2019/06/27 Javascript
Python操作sqlite3快速、安全插入数据(防注入)的实例
2014/04/26 Python
python 递归遍历文件夹,并打印满足条件的文件路径实例
2017/08/30 Python
Python使用matplotlib实现基础绘图功能示例
2018/07/03 Python
python中单例常用的几种实现方法总结
2018/10/13 Python
python中报错&quot;json.decoder.JSONDecodeError: Expecting value:&quot;的解决
2019/04/29 Python
python实现单链表的方法示例
2019/09/03 Python
python的faker库用法
2019/11/28 Python
Django 返回json数据的实现示例
2020/03/05 Python
Python类的动态绑定实现原理
2020/03/21 Python
美国最好的保健品打折网店:Swanson
2017/08/04 全球购物
英国床和浴室商场:Bed & Bath Emporium
2018/05/20 全球购物
存储过程的优缺点是什么
2015/01/10 面试题
幼儿园教师节感谢信
2015/01/23 职场文书
2016孝老爱亲模范事迹材料
2016/02/26 职场文书
Python中的嵌套循环详情
2022/03/23 Python
SpringBoot项目多数据源及mybatis 驼峰失效的问题解决方法
2022/07/07 Java/Android