摘要:对于迭代器来说,返回的是它自身,则是返回迭代器中的下一个值,如果没有值了则抛出一个的异常。有一点绕,我们再来理一理迭代器和可迭代这两个的差别一个迭代器一定是可迭代对象,因为它一定有方法。而可迭代对象的方法通常会生成一个新的迭代器对象。
for 循环 是我们在 Python 里非常常用的一个语法,但你有没有思考过 for 循环是怎样实现的?
如果你以前接触过 C++,应该会知道类似 for (int i = 0; i < 100; i++) 这样的写法,它定义了 循环的执行条件 i < 100 以及 每次循环结束后执行的语句 i++,而 for 本身只起到让代码重复执行的作用,并没有什么额外的功能。这在 Python 中其实更像是 while 循环:
i = 0 while i < 100: # 执行循环代码 i += 1
但 Python 里的 for 循环却不一样。使用 for 时,我们没有额外指定结束条件,也不需要一个用来计数的数值,甚至可以通过一个字符串进行循环。之所以可以这样,是因为 Python 中的 迭代器(Iterator) 以及 可迭代对象(Iterable) 。
如果一个对象定义了 __iter__ 和 __next__ 两个方法, 它就是一个迭代器 。对于迭代器来说,__iter__ 返回的是它自身 self ,__next__ 则是 返回迭代器中的下一个值 ,如果没有值了则抛出一个 StopIteration 的异常。关于这点,你可以想象成一个只进不退的标记位,每次调用 __next__,就会将标记往后移一个元素并返回,直到结束。
有了迭代器的概念之后,如果一个对象定义了 __iter__ 和方法,返回一个迭代器对象,那么 它就是一个可迭代的对象 。
从表现上来说,一个对象 可迭代 ,那么它就可以被 for 循环使用。比如我们经常用到的 list、dict、str 等类型,都是可迭代的,所以也就可以通过 for 循环进行遍历,或者更准确的说:被迭代。
有一点绕,我们再来理一理迭代器(Iterator)和可迭代(Iterable)这两个的差别:
一个 迭代器一定是可迭代对象 ,因为它一定有 __iter__ 方法。反过来则不成立。(事实上,Iterator 就是 Iterable 的子类)
迭代器的 __iter__ 方法 返回的是自身,并不产生新实例 。而可迭代对象的 __iter__ 方法通常会生成一个新的迭代器对象。
__iter__、__next__ 分别对应于 Python 的内置函数 iter() 和 next():比如 iter(aList) 就相当于 aList.__iter__()。
所以关于上述两点,我们可以有以下的例子来验证:
迭代器和可迭代之间的继承关系。
__iter__ 方法返回值的区别。id 相同代表是同一个实例。
明白了上述的概念之后,for 循环的实现就好理解了:
首先 for 循环会调用可迭代对象的 __iter__ 方法,获取相应的迭代器
每次循环,将迭代器的 __next__ 方法的返回值赋值给循环变量
直到捕获迭代器抛出的 StopIteration 异常,循环结束
再来看个例子:
思考题: 想一想为什么迭代器 aListIter 被 for 循环迭代第二次的时候就没有输出了?
既然 __next__ 方法可以自己定义,我们也可以自己实现一个迭代器。比如要 输出一个斐波那契数列 (每一位数值都是前两位数值之和,原题回复关键字 906 ),通常的做法是循环,“高级”一点的做法是递归。但我们也可以直接写一个斐波那契迭代器:
# 定义迭代器 class Fibonacci(): def __init__(self): self.a = 0 self.b = 1 def __iter__(self): return self def __next__(self): # 结束条件 if self.b > 100: raise StopIteration # 更新一次数值 self.a, self.b = self.b, self.a + self.b return self.a # 创建迭代器 fib = Fibonacci() # 进行迭代 for f in fib: print(f, end=" ")
输出:
1 1 2 3 5 8 13 21 34 55 89
这个例子中,我们并没有保存一个序列,只是定义了一种规则,就也可以被迭代。
使用迭代器的好处在于:它是一种 延迟操作 ,即当需要用到的时候才去产生结果。比如对于一个序列来说,如果我们要遍历它,并不需要再一开始就把所有元素都生成好,而是只需要知道每个元素的下一个元素是什么就可以了。这样可以节省很多空间,尤其对于数量很大的集合来说。
如果你不懂迭代器的概念,并不影响在代码中使用 for 循环。但了解之后,你会对代码理解得更透彻,同时这也是为我们后面要讲到的 生成器 做铺垫。
════
其他文章及回答:
如何自学Python | 新手引导 | 精选Python问答 | Python单词表 | 人工智能 | 爬虫 | 我用Python | requests | 计算机视觉 | 字符播放器 | 一图学Python
欢迎搜索及关注公众号: Crossin的编程教室
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/43200.html
摘要:简评迭代器是惰性可迭代对象,函数在中是一个惰性的可迭代对象,那么是不是迭代器呢为什么。如果你不能将某些东西传递给函数,那么它不是一个迭代器。的对象不是迭代器。 简评:迭代器(iterator)是惰性可迭代对象(lazy iterable),range 函数在 Python 3 中是一个惰性的可迭代对象,那么 range 是不是迭代器呢?为什么。 TLNR:Python 3 中的 ran...
摘要:本文从使用对数组进行遍历开始说起,粗略对比使用进行遍历的差异,并由此引入中可迭代对象迭代器的概念,并对其进行粗略介绍。说到这里,就继续说一下迭代器关闭的情况了。确实,符合可迭代协议和迭代器协议的。 本文从使用 forEach 对数组进行遍历开始说起,粗略对比使用 forEach , for...in , for...of 进行遍历的差异,并由此引入 ES6 中 可迭代对象/迭代器 的概...
摘要:本文重点掌握可迭代的对象的定义掌握可迭代对象迭代器与生成器之间的关系和异同熟悉标准库中生成器。二迭代器迭代器介绍迭代器用于从集合中取出元素的对象。若想再次迭代须重建迭代器。迭代器检查方式调用,。区别可迭代的对象不是迭代器。 导语:本文章记录了本人在学习Python基础之控制流程篇的重点知识及个人心得,打算入门Python的朋友们可以来一起学习并交流。 本文重点: 1、掌握可迭代的对象的...
摘要:通过生成器创建的迭代器也是可迭代对象,因为生成器默认会为属性赋值。我们可以用来访问对象的默认迭代器,例如对于一个数组获得了数组这个可迭代对象的默认迭代器,并操作它遍历了数组中的元素。 ES6 新的数组方法、集合、for-of 循环、展开运算符(...)甚至异步编程都依赖于迭代器(Iterator )实现。本文会详解 ES6 的迭代器与生成器,并进一步挖掘可迭代对象的内部原理与使用方法 ...
阅读 3297·2021-11-16 11:45
阅读 2653·2021-09-22 15:23
阅读 563·2021-07-30 14:58
阅读 459·2019-08-30 15:54
阅读 2234·2019-08-29 16:19
阅读 3015·2019-08-29 12:45
阅读 934·2019-08-23 17:57
阅读 1788·2019-08-23 17:54