for循环在Python中的工作原理详细

例如:

作用于列表

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

作用于字符串

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

作用于字典

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

可能有人不经要问,为什么这么多不同类型对象都支持 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 自己会处理,不会暴露给开发者

对于元组,字典,字符串也是同样的道理,弄明白了 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循环中。

到此这篇关于for循环在Python中的工作原理详细的文章就介绍到这了,更多相关for循环在Python中的工作原理内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • python入门for循环嵌套理解学习

    目录 for循环的格式 for循环语句格式 1.通过for循环遍历字符串 2.通过for循环遍历列表 3.通过for循环计算1-100的和 4.通过for循环打印九九乘法表 上一一节我们讲了while循环,while循环主要用于重复程序的运行,for循环更加倾向于遍历一个项目,即将特定内容(比如一个列表.一个字符串.一个字典的内容)通过for循环依次展现. for循环的格式 for循环语句格式 接下来我们通过实例来具体讲解for循环的使用: 1.通过for循环遍历字符串 通过for循环遍历字符串

  • 解决python 在for循环并且pop数组的时候会跳过某些元素的问题

    今天在学python的时候遇到一个问题,循环一个数组 指定一个数,如果数组内有相同的元素就删除. 1. 前提是不能新增内存,就在该数组内处理 nums = [0,1,2,2,3,0,4,2] val = 2 for i in nums: if(i == val): idx = nums.index(i) nums.pop(idx) print(nums) 一开始写成这样时候输出 [0, 1, 2, 3, 0, 4] //中间的2居然没有删除 然后我修改了一下 把每一次循环都打出来看看 0loop

  • python for循环赋值问题

    背景 写代码的时候,你会发现你的代码越写越多. 然而,功能需要也越来越多,然后你的冗余代码就多得不能再多了~~~怎么办,我太难了. 那就寻求一些高级写法,一般的高级写法都是尽可能地短. 另外,把重复的代码抽取出来,封装成函数,每次使用直接调函数即可. For循环赋值 前提条件:我创建了一个road类,这个类里面有这些属性.我先初始化给road赋值,然后再把这些对象放到roadObjList集合里面. 目标:从roadObjList集合里面取出每个road对象的objectid值,然后放入到新的列

  • Python 如何用一行代码实现for循环初始化数组

    我就废话不多说了,大家还是直接看代码吧~ # 用一行代码实现for循环初始化数组 o = 10 b = [ o + u for u in range( 10 ) ] print( b ) # 结果是 [10, 11, 12, 13, 14, 15, 16, 17, 18, 19] x = 2 y = 3 c = [ i * y + x for i in range( 10 ) ] print( c ) # 结果是 [2, 5, 8, 11, 14, 17, 20, 23, 26, 29] 补充:

  • Python for循环搭配else常见问题解决

    这篇文章主要介绍了Python for循环搭配else常见问题解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 假设有如下代码: for i in range(10): if i == 5: print 'found it! i = %s' % i else: print 'not found it ...' 你期望的结果是,当找到5时打印出 found it! i = 5 实际上打印出来的结果为: found it! i = 5 not f

  • python3中for循环踩过的坑记录

    前言 最近在用python练习写点爬虫,想着把双色球的历史记录爬下来存入mysql中,爬取数据没有遇到什么问题,在处理数据存入数据库的时候遇到问题了,现把问题整理出来方便自己日后查询也能帮助有缘人士: 一.从双色球历史网站爬取数据存成html文件: import urllib.request url = 'https://datachart.500.com/ssq/history/newinc/history.php?start=1&end=20109' request = urllib.req

  • Python利用for循环打印星号三角形的案例

    简单的for循环打印三角形 1,for循环方法实现星星三角 代码: for i in range(0,5): for j in range(i+1): if i == 4: print("* ",end="") continue if j == 0 or j == i: print("* ",end="") else: print(" ",end="") print() 2.实心三角:

  • python for循环内输出和外输出方式

    通过for循环求和,结果发现输出完全不一样,一个循环是输出每一步的结果,另一个循环是输出最终一次的结果,今天终于弄懂了. 如下所示: 补充:python中for循环输出(index,value)的两种方法 index索引 value索引值 方法一.利用enumerate() list1=['a','s','d','g'] for index,value in enumerate(list1): print('索引:%d,索引值:%s'%(index,value)) 输出结果: 索引:0,索引值:

  • Python for循环通过序列索引迭代过程解析

    这篇文章主要介绍了Python for循环通过序列索引迭代过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 Python for 循环通过序列索引迭代: 注:集合 和 字典 不可以通过索引进行获取元素,因为集合和字典都是无序的. 使用 len (参数) 方法可以获取到遍历对象的长度. 程序: strs = "Hello World." # 使用 len 方法可以获取到遍历对象的长度. print(len(strs)) # 12

  • for循环在Python中的工作原理详细

    例如: 作用于列表 >>> for elem in [1,2,3]: ... print(elem) ... 1 2 3 作用于字符串 >>> for c in "abc": ... print(c) ... a b c 作用于字典 >>> for k in {"age":10, "name":"wang"}: ... print(k) ... age name 可能有人不

  • Python中的浮点数原理与运算分析

    本文实例讲述了Python中的浮点数原理与运算.分享给大家供大家参考,具体如下: 先看一个违反直觉的例子: >>> s = 0. >>> for i in range(10): s += .1 >>> s 0.9999999999999999 # 错误被累加 再看一个更为普遍,直接影响判断逻辑的例子: >>> from math import sqrt >>> a = sqrt(2) >>> a*a

  • python中GIL的原理及用法总结

    1.说明 GIL规定一个Python解释程序只能同时由一个线程控制. 在CPU限制类型和多线程代码中,GIL是一个性能瓶颈. GIL使Python多线程成为伪并行多线程. 仅CPython解释器上存在GIL. 2.原理 (1)线程1.2.3轮流执行,每一个线程在执行是,都会锁住GIL,以阻止别的线程执行: 同样的,每一个线程执行一段后,会释放GIL,以允许别的线程开始利用资源. (2)由于古老GIL机制,如果线程2需要在CPU2上执行,它需要先等待在CPU1上执行的线程1释放GIL(记住:GIL

  • Android中SurfaceFlinger工作原理

    概念 SurfaceFlinger是一个系统服务,如:audioflinger,audiopolicyservice等等,系统的主要服务通过这个文章进行了解,Android的系统服务一览.这个系统服务主要实现了Surface的建立.控制.管理等功能.换种说法就是,在Android 的实现中它是一个service,提供系统范围内的surface composer功能,它能够将各种应用程序的2D.3D surface进行组合. 原理分析 让我们首先看一下下面的屏幕简略图: 每个应用程序可能对应着一个

  • 一文详解Python中生成器的原理与使用

    目录 什么是生成器 迭代器和生成器的区别 创建方式 生成器表达式 基本语法 生成器函数 yield关键字 yield和return yield的使用方法 生成器函数的基本使用 send的使用 可迭代对象的优化 总结 我们学习完推导式之后发现,推导式就是在容器中使用一个for循环而已,为什么没有元组推导式? 原因就是“元组推导式”的名字不是这样的,而是叫做生成器表达式. 什么是生成器 生成器表达式本质上就是一个迭代器,是定义迭代器的一种方式,是允许自定义逻辑的迭代器.生成器使用generator表

  • 详解Python中递归函数的原理与使用

    目录 什么是递归函数 递归函数的条件 定义一个简单的递归函数 代码解析 内存栈区堆区 死递归 尾递归 实例 什么是递归函数 如果一个函数,可以自己调用自己,那么这个函数就是一个递归函数. 递归,递就是去,归就是回,递归就是一去一回的过程. 递归函数的条件 一般来说,递归需要边界条件,整个递归的结构中要有递归前进段和递归返回段.当边界条件不满足,递归前进,反之递归返回.就是说递归函数一定需要有边界条件来控制递归函数的前进和返回. 定义一个简单的递归函数 # 定义一个函数 def recursion

  • 详解JSP 中Spring工作原理及其作用

    详解JSP 中Spring工作原理及其作用 1.springmvc请所有的请求都提交给DispatcherServlet,它会委托应用系统的其他模块负责负责对请求进行真正的处理工作. 2.DispatcherServlet查询一个或多个HandlerMapping,找到处理请求的Controller. 3.DispatcherServlet请请求提交到目标Controller 4.Controller进行业务逻辑处理后,会返回一个ModelAndView 5.Dispathcher查询一个或多个

  • python中栈的原理及实现方法示例

    本文实例讲述了python中栈的原理及实现方法.分享给大家供大家参考,具体如下: 栈(stack),有些地方称为堆栈,是一种容器,可存入数据元素.访问元素.删除元素,它的特点在于只能允许在容器的一端(称为栈顶端指标,英语:top)进行加入数据(英语:push)和输出数据(英语:pop)的运算.没有了位置概念,保证任何时候可以访问.删除的元素都是此前最后存入的那个元素,确定了一种默认的访问顺序. 由于栈数据结构只允许在一端进行操作,因而按照后进先出(LIFO, Last In First Out)

  • Python中顺序表原理与实现方法详解

    本文实例讲述了Python中顺序表原理与实现方法.分享给大家供大家参考,具体如下: Python中的顺序表 Python中的list和tuple两种类型采用了顺序表的实现技术,具有顺序表的所有性质. tuple是不可变类型,即不变的顺序表,因此不支持改变其内部状态的任何操作,而其他方面,则与list的性质类似. list的基本实现技术 Python标准类型list就是一种元素个数可变的线性表,可以加入和删除元素,并在各种操作中维持已有元素的顺序(即保序),而且还具有以下行为特征: 基于下标(位置

  • ASP.NET Core MVC中过滤器工作原理介绍

    过滤器的作用是在 Action 方法执行前或执行后做一些加工处理.使用过滤器可以避免Action方法的重复代码,例如,您可以使用异常过滤器合并异常处理的代码. 过滤器如何工作? 过滤器在 MVC Action 调用管道中运行,有时称为过滤器管道.MVC选择要执行的Action方法后,才会执行过滤器管道: 实现 过滤器同时支持同步和异步两种不同的接口定义.您可以根据执行的任务类型,选择同步或异步实现. 同步过滤器定义OnStageExecuting和OnStageExecuted方法,会在管道特定

随机推荐