![]() 无论是面试测试还是运维涉及到python编码岗位时,迭代器和可迭代对象都是绕不开的一个问题,本文对这两个概念进行重点讲解,本文从什么是迭代讲起,然后介绍迭代器和可迭代对象二者的区别,最后通过for 循环和自定义迭代器来加深读者对这两个概念的理解,只要认真阅读完文章,相信一定会帮助到大家,文章有点长,建议首收藏! 迭代关于迭代,维基百科是这样子定义的:迭代是重复反馈过程的活动,其目的通常是为了接近并到达所需的目标或结果。每一次对过程的重复被称为一次“迭代”,而每一次迭代得到的结果会被用来作为下一次迭代的初始值。 在程序中,迭代是一种遍历集合元素的方式,我们最常用的迭代应用如下: for i in [1,2,3]: print(i) 输出: 1 2 3 可迭代对象(iterable)只要实现 __ iter __ 方法或者实现 __ getitem __方法而且其参数从0开始索引,那么该对象就是可迭代对象(iterable)。 Python 中的大多数内置数据结构(容器)都是可迭代对象,比如list、dict、tuple、set、string。创建一个可迭代对象的实例如下:
输出 1 2 3 可以看到实例IterableDemo进行了迭代,该对象之所以能迭代,是因为实现了__ iter __ ()方法。当使用for循环时候,解释器会检查对象是否有__ iter __ ()方法,有的话就是调用它来获取一个迭代器。所以没有 __ iter __ ()方法但实现了__ getitem __ (),解释器会创建一个迭代器,尝试从0开始按顺序遍历元素。如果尝试失败,Python便会抛出TypeError错误。 看下面这个list的例子,l=[1,2,3]。这里 l是一个可迭代对象。 我们可以通过方法__iter__()和函数iter把list(可迭代对象)转变成list迭代器对象,代码如下 print(type(l))print(type(l.__iter__()))print(type(iter(l))) 输出 <class 'list'> <class 'list_iterator'> <class 'list_iterator'> 我们可以看到,list变成了list_iterator,证明list是可迭代对象! a=123456 print(type(iter(a))) 输出 TypeError: 'int' object is not iterable 可见int 类型是不可迭代对象,也就是说调用iter(对象)函数,如果该对象不可迭代,就会抛出TypeError的错误。 迭代器(iterator)Python 中的迭代器是一个可以迭代的对象,一个每次仅仅返回一个元素的对象。从技术上讲,Python 迭代器对象必须实现两个魔法方法:__iter__() 和 __next__()方法,统称为迭代器协议(iterator protocol)。 容器是一种把多个元素组织在一起的数据结构,容器中的元素可以逐个地迭代获取,可以用 in , not in 关键字判断元素是否包含在容器中。通常这类数据结构把所有的元素存储在内存中(也有一些特列并不是所有的元素都放在内存)在Python中,常见的容器对象有:list、dequeue、set、dict、Counter、tuple、str等等。尽管绝大多数容器都提供了某种方式来获取其中的每一个元素,但这并不是容器本身提供的能力,而是 可迭代对象 赋予了容器这种能力,当然并不是所有的容器都是可迭代的(Bloom filter容器不可以迭代)。我们执行以下代码,创建x 和y两个独立的迭代器。
输出 y第一次调用:1 x第一次调用:1 y第二次调用:2 x第二次调用:2 证明了 1. x、y是两个独立的迭代器,彼此不影响 2. 迭代器内部持有一个状态,该状态用于记录当前迭代所在的位置,调用next,每次都是按顺序获取对应的元素 那么究竟什么是迭代器呢? 迭代器是一个可以记住遍历位置的对象,其内部有一个状态用于记录迭代所在的位置,以便下次迭代时候能取出正确的元素。迭代器就像一个懒人一样,当你需要数据时候才会返回给你,否则就在等待下一次的调用。 迭代器技术主要应用在哪些地方呢?主要包括: · for 循环 · 构建和扩展集合类型 · 逐行遍历文本文件 · 列表推导、字典推导和集合推导 · 元组拆包 · 调用函数时,使用*拆包 迭代器和可迭代对象总结共性:他们都可以通过循环的形式进行迭代; 迭代器是可迭代对象, 但是可迭代对象不一定是迭代器,例如list是可迭代对象,但不是迭代器; 可以通过iter(可迭代对象)的方法来生成迭代器; 可迭代对象需要实现 __ iter __ 方法或者实现 __ getitem __方法而且其参数从0开始索引。注意可迭代对象不一定实现__ next__方法; 迭代器需要同时实现__ iter __ 方法和__next__ 方法,当使用next()函数时会调用__next__方法。 举一个经典的例子把 l=[1,2,3]print(next(l)) 输出error: print(next(l)) TypeError: 'list' object is not an iterator 可见,list不是一个迭代器,因为他没有实现__next__方法 接下来执行代码,print(next(iter(l))) 输出 1 可见通过iter(l) 生成了迭代器,因此next操作可以顺利进行 for i in (iterable)的内部实现在大多数情况下,我们不会一次次调用next方法去取值,而是通过 for i in (iterable)的方式,如下图: ![]() 循环背后的原理又是什么呢? 调用iter(容器对象,即可迭代对象,即上图中的x=[1,2,3])函数生成迭代器(如果调用成功) 通过迭代器的__next__()方法访问容器元素 如果没有元素了,将抛出StopIteration exception 循环捕获StopIteration exception后就会终止循环 自定义迭代器如果想自定义迭代器,需要实现__iter_和__next__两个方法
输出: True 1 2 3 4 5 从输出结果可以看出my 是iterable对象,并完成了遍历工作! 大家可以自定义一个类,里面不实现__iter_和__next__两个方法,例如 class Demo: passdemo= Demo()print(type(iter(demo))) 输出: TypeError: 'Demo' object is not iterable |
|