详解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解析发往本机的数据包示例 (解析数据包)
Jan 16 Python
python实现外卖信息管理系统
Jan 11 Python
Python实现识别手写数字 Python图片读入与处理
Mar 23 Python
python爬虫 使用真实浏览器打开网页的两种方法总结
Apr 21 Python
详解python3中tkinter知识点
Jun 21 Python
浅谈python写入大量文件的问题
Nov 09 Python
如何在Python中实现goto语句的方法
May 18 Python
Python with关键字,上下文管理器,@contextmanager文件操作示例
Oct 17 Python
python实现超级玛丽游戏
Mar 18 Python
python 读txt文件,按‘,’分割每行数据操作
Jul 05 Python
Python word文本自动化操作实现方法解析
Nov 05 Python
理解python中装饰器的作用
Jul 21 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表单递交控件名称含有点号(.)会被转化为下划线(_)的处理方法
2013/01/06 PHP
PHP生成不重复标识符的方法
2014/11/21 PHP
Symfony2开发之控制器用法实例分析
2016/02/05 PHP
php实现三级级联下拉框
2016/04/17 PHP
PHP解压ZIP文件到指定文件夹的方法
2016/11/17 PHP
Extjs实现进度条的两种便捷方式
2013/09/26 Javascript
html的DOM中document对象images集合用法实例
2015/01/21 Javascript
Javascript编写俄罗斯方块思路及实例
2015/07/07 Javascript
jq实现左侧显示图片右侧文字滑动切换效果
2015/08/04 Javascript
jQuery操作属性和样式详解
2016/04/13 Javascript
js判断空对象的实例(超简单)
2016/07/26 Javascript
jQuery中get方法用法分析
2016/12/07 Javascript
vuejs开发组件分享之H5图片上传、压缩及拍照旋转的问题处理
2017/03/06 Javascript
React Js 微信禁止复制链接分享禁止隐藏右上角菜单功能
2017/05/26 Javascript
基于Vuejs的搜索匹配功能实现方法
2018/03/03 Javascript
Python调用命令行进度条的方法
2015/05/05 Python
使用Python读取安卓手机的屏幕分辨率方法
2018/03/31 Python
python迭代dict的key和value的方法
2018/07/06 Python
使用Python向C语言的链接库传递数组、结构体、指针类型的数据
2019/01/29 Python
python selenium爬取斗鱼所有直播房间信息过程详解
2019/08/09 Python
tensorflow 只恢复部分模型参数的实例
2020/01/06 Python
django orm模块中的 is_delete用法
2020/05/20 Python
详解Anaconda安装tensorflow报错问题解决方法
2020/11/01 Python
Python爬虫自动化获取华图和粉笔网站的错题(推荐)
2021/01/08 Python
阿迪达斯丹麦官网:adidas丹麦
2016/10/01 全球购物
Tom Dixon官网:英国照明及家具设计和制造公司
2019/03/01 全球购物
物流管理专业大学生自荐信
2013/10/04 职场文书
女儿十岁生日答谢词
2014/01/27 职场文书
领导班子群众路线与四风问题对照检查材料思想汇报
2014/10/11 职场文书
成绩单评语
2015/01/04 职场文书
圆明园观后感
2015/06/03 职场文书
网吧温馨提示
2015/07/17 职场文书
小学记事作文之200字
2019/08/06 职场文书
一篇文章了解正则表达式的替换技巧
2022/02/24 Javascript
DE1103使用报告
2022/04/05 无线电
ConditionalOnProperty配置swagger不生效问题及解决
2022/06/14 Java/Android