Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >​Python迭代器

​Python迭代器

原创
作者头像
忆想不到的晖
修改于 2021-04-06 03:27:06
修改于 2021-04-06 03:27:06
5670
举报
文章被收录于专栏:huihui

迭代器

迭代是访问集合元素的一种方式。迭代器是一个可以记住遍历的位置的对象。迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。

可迭代对象

我们已经知道可以对 list、tuple、str 等类型的数据使用 for...in... 的循环语法从其中依次拿到数据进行使用,我们把这样的过程称为遍历,也叫迭代

但是,是否所有的数据类型都可以放到 for...in... 的语句中,然后让 for...in... 每次从中取出一条数据供我们使用,即供我们迭代吗?

代码语言:txt
AI代码解释
复制
>>> for i in 100:
...     print(i)
...
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'int' object is not iterable
>>>

很明显 int 整型不是 iterable,即 int 整型是不可以迭代的

代码语言:txt
AI代码解释
复制
# 我们自定义一个容器MyList用来存放数据,可以通过add方法向其中添加数据
>>> class MyList(object):
...     def __init__(self):
...             self.container = []
...     def add(self, item):
...             self.container.append(item)
...
>>> mylist = MyList()
>>> mylist.add(1)
>>> mylist.add(2)
>>> mylist.add(3)
>>> for num in mylist:
...     print(num)
...
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'MyList' object is not iterable
>>>
# MyList容器的对象也是不能迭代的

我们自定义了一个容器类型 MyList,在将一个存放了多个数据的 MyList 对象放到 for...in... 的语句中,发现 for...in... 并不能从中依次取出一条数据返回给我们,也就说我们随便封装了一个可以存放多条数据的类型却并不能被迭代使用。

我们把可以通过 for...in... 这类语句迭代读取一条数据供我们使用的对象称之为 可迭代对象(Iterable)

如何判断一个对象是否可以迭代

可以使用 isinstance() 判断一个对象是否是 Iterable 对象:

代码语言:txt
AI代码解释
复制
In [1]: from collections import Iterable

In [2]: isinstance([], Iterable)
Out[2]: True

In [3]: isinstance({}, Iterable)
Out[3]: True

In [4]: isinstance('abc', Iterable)
Out[4]: True

In [5]: isinstance(mylist, Iterable)
Out[5]: False

In [6]: isinstance(100, Iterable)
Out[6]: False

可迭代对象的本质

我们分析对可迭代对象进行迭代使用的过程,发现每迭代一次(即在 for...in... 中每循环一次)都会返回对象中的下一条数据,一直向后读取数据直到迭代了所有数据后结束。那么,在这个过程中就应该有一个 “人” 去记录每次访问到了第几条数据,以便每次迭代都可以返回下一条数据。

我们把这个能帮助我们进行数据迭代的 “人” 称为 迭代器(Iterator)

可迭代对象的本质就是可以向我们提供一个这样的中间“人”即迭代器帮助我们对其进行迭代遍历使用。

可迭代对象通过 __iter__() 方法向我们提供一个迭代器,我们在迭代一个可迭代对象的时候,实际上就是先获取该对象提供的一个迭代器,然后通过这个迭代器来依次获取对象中的每一个数据.

那么也就是说,一个具备了 __iter__() 方法的对象,就是一个可迭代对象。

代码语言:txt
AI代码解释
复制
from collections import Iterable


class MyList(object):
     def __init__(self):
             self.container = []
                
     def add(self, item):
             self.container.append(item)
            
     def __iter__(self):
             """返回一个迭代器"""
             # 我们暂时忽略如何构造一个迭代器对象
             pass

mylist = MyList()

isinstance(mylist, Iterable) # True

这回测试发现添加了 __iter__() 方法的 mylist 对象已经是一个可迭代对象了

iter()函数与next()函数

list、tuple等都是可迭代对象,我们可以通过 iter() 函数获取这些可迭代对象的迭代器。然后对获取到的迭代器不断使用 next() 函数来获取下一条数据。 iter() 函数实际上就是调用了可迭代对象的 __iter__ 方法

我们使用 ipython 来调试一下

代码语言:txt
AI代码解释
复制
In [8]: li = [11, 22, 33, 44, 55]

In [9]: li_iter = iter(li)

In [10]: next(li_iter)
Out[10]: 11

In [11]: next(li_iter)
Out[11]: 22

In [12]: next(li_iter)
Out[12]: 33

In [13]: next(li_iter)
Out[13]: 44

In [14]: next(li_iter)
Out[14]: 55

In [15]: next(li_iter)
---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-15-ab6a83f394a1> in <module>
----> 1 next(li_iter)

StopIteration:

In [16]:                                          

<font color=red>注意:</font> 当我们已经迭代完最后一个数据之后,再次调用 next() 函数会抛出 StopIteration 的异常,来告诉我们所有数据都已迭代完成,不用再执行 next() 函数了。

如何判断一个对象是否是迭代器

可以使用 isinstance() 判断一个对象是否是 Iterator 对象:

代码语言:txt
AI代码解释
复制
In [6]: from collections import Iterator

In [7]: isinstance([], Iterator)
Out[7]: False

In [8]: isinstance(iter([]), Iterator)
Out[8]: True

In [9]: isinstance(iter("abc"), Iterator)
Out[9]: True

迭代器Iterator

通过上面的分析,我们已经知道,迭代器是用来帮助我们记录每次迭代访问到的位置,当我们对迭代器使用 next() 函数的时候,迭代器会向我们返回它所记录位置的下一个位置的数据。实际上,在使用 next() 函数的时候,调用的就是迭代器对象的 __next__ 方法(Python3中是对象的 __next__ 方法,Python2中是对象的next() 方法)。所以,我们要想构造一个迭代器,就要实现它的__next__方法。但这还不够,python要求迭代器本身也是可迭代的,所以我们还要为迭代器实现 __iter__ 方法,而 __iter__ 方法要返回一个迭代器,迭代器自身正是一个迭代器,所以迭代器的 __iter__ 方法返回自身即可。

一个实现了 __iter__ 方法和 __next__ 方法的对象,就是迭代器。

代码语言:txt
AI代码解释
复制
class MyList(object):
    """自定义的一个可迭代对象"""
    def __init__(self):
        self.items = []

    def add(self, val):
        self.items.append(val)

    def __iter__(self):
        myiterator = MyIterator(self)
        return myiterator


class MyIterator(object):
    """自定义的供上面可迭代对象使用的一个迭代器"""
    def __init__(self, mylist):
        self.mylist = mylist
        # current用来记录当前访问到的位置
        self.current = 0

    def __next__(self):
        if self.current < len(self.mylist.items):
            item = self.mylist.items[self.current]
            self.current += 1
            return item
        else:
            raise StopIteration

    def __iter__(self):
        return self

   
def main():
    mylist = MyList()
    mylist.add(1)
    mylist.add(2)
    mylist.add(3)
    mylist.add(4)
    mylist.add(5)
    
    for num in mylist:
        print(num)
        
        
if __name__ == '__main__':
    main()

运行结果:

代码语言:txt
AI代码解释
复制
1
2
3
4
5
[Finished in 0.1s]

for...in...循环的本质

for item in Iterable 循环的本质就是先通过 iter()函数 获取可迭代对象 Iterable 的迭代器,然后对获取到的迭代器不断调用 next() 方法来获取下一个值并将其赋值给 item,当遇到 StopIteration的异常后循环结束。

因此我们可以根据其原理改成 while 循环遍历

代码语言:txt
AI代码解释
复制
def main():
    mylist = MyList()
    mylist.add(1)
    mylist.add(2)
    mylist.add(3)
    mylist.add(4)
    mylist.add(5)
    
    # for num in mylist:
    #     print(num)

    myli_iter = iter(mylist) # 获取迭代器对象
    while True:
        try:
            item = next(myli_iter)
            print(item)
        except StopIteration:
            break
        

if __name__ == '__main__':
    main()

迭代器的应用场景

我们发现迭代器最核心的功能就是可以通过 next()函数 的调用来返回下一个数据值。如果每次返回的数据值不是在一个已有的数据集合中读取的,而是通过程序按照一定的规律计算生成的,那么也就意味着可以不用再依赖一个已有的数据集合,也就是说不用再将所有要迭代的数据都一次性缓存下来供后续依次读取,这样可以节省大量的存储(内存)空间。

举个例子,比如,数学中有个著名的 斐波拉契数列(Fibonacci),数列中第一个数为0,第二个数为1,其后的每一个数都可由前两个数相加得到:

代码语言:txt
AI代码解释
复制
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, ...

现在我们想要通过 for...in... 循环来遍历迭代斐波那契数列中的前n个数。那么这个斐波那契数列我们就可以用迭代器来实现,每次迭代都通过数学计算来生成下一个数。

代码语言:txt
AI代码解释
复制
class FibIterator(object):
    """斐波那契数列迭代器"""
    def __init__(self, n):
        """
        :param n: int, 指明生成数列的前n个数
        """
        self.n = n
        # current用来保存当前生成到数列中的第几个数了
        self.current = 0
        # num1用来保存前前一个数,初始值为数列中的第一个数0
        self.num1 = 0
        # num2用来保存前一个数,初始值为数列中的第二个数1
        self.num2 = 1

    def __next__(self):
        """被next()函数调用来获取下一个数"""
        if self.current < self.n:
            num = self.num1
            self.num1, self.num2 = self.num2, self.num1+self.num2
            self.current += 1
            return num
        else:
            raise StopIteration

    def __iter__(self):
        """迭代器的__iter__返回自身即可"""
        return self


if __name__ == '__main__':
    fib = FibIterator(10)
    for num in fib:
        print(num, end=" ")

并不是只有for循环能接收可迭代对象

除了 for循环 能接收可迭代对象,list、tuple、set 等也能接收。

代码语言:txt
AI代码解释
复制
li = list(FibIterator(10))
tp = tuple(FibIterator(10))
s = set(FibIterator(10))

print(li)
print(tp)
print(s)

结果如下:

代码语言:txt
AI代码解释
复制
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
(0, 1, 1, 2, 3, 5, 8, 13, 21, 34)
{0, 1, 2, 3, 34, 5, 8, 13, 21}

注意 set 集合去重了。

公众号

新建文件夹X

大自然用数百亿年创造出我们现实世界,而程序员用几百年创造出一个完全不同的虚拟世界。我们用键盘敲出一砖一瓦,用大脑构建一切。人们把1000视为权威,我们反其道行之,捍卫1024的地位。我们不是键盘侠,我们只是平凡世界中不凡的缔造者 。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Python 迭代器 - Iterable对象
迭代是访问集合元素的一种方式。迭代器是一个可以记住遍历的位置的对象。迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。
Devops海洋的渔夫
2019/06/02
2.2K0
爬虫 (二十三) python 迭代器详解 (十四)
相信如果你慢慢把这篇文章读完,然后加以实践,你会对 python 文件操作会有很大的理解,加油看完哦
公众号---人生代码
2020/01/14
5970
爬虫 (二十三) python 迭代器详解 (十四)
迭代器Python_python进阶路线
迭代是访问集合元素的一种方式。迭代器是一个可以记住遍历的位置的对象。迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。
全栈程序员站长
2022/09/19
2570
【从零学习python 】59.迭代器:优化数据遍历的高效工具
迭代是访问集合元素的一种方式。迭代器是一个可以记住遍历的位置的对象。迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。
全栈若城
2024/02/29
1580
学习Python一年,基础忘记了,看看面试题回忆回议,Python面试题No3
git,svn两个都要说到,github,码云也要提及,面试官想要的就是版本管理工具,你只要选择一个你熟悉的,疯狂的说一通就可以了,最好说一下自己以前做过哪些开源的项目,放在上面,没有,就另当别论了。
梦想橡皮擦
2019/05/15
5070
【从零学习python 】60.探索生成器:迭代的灵活利器
利用迭代器,我们可以在每次迭代获取数据(通过next()方法)时按照特定的规律进行生成。但是我们在实现一个迭代器时,关于当前迭代到的状态需要我们自己记录,进而才能根据当前状态生成下一个数据。为了达到记录当前状态,并配合next()函数进行迭代使用,我们可以采用更简便的语法,即生成器(generator)。生成器是一类特殊的迭代器。
全栈若城
2024/02/29
1000
Python基础|一文讲透 Python 协程
在类里面提供一个__iter__创建的对象是可迭代对象,可迭代对象是需要迭代器完成数据迭代的
陈晨135
2022/01/10
4790
Fibonacci数列使用迭代器实现
Fibonacci数列,数列中第一个数为0,第二个数为1,其后的每一个数都可由前两个数相加得到: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, ... class FibIterator(object): """斐波那契数列迭代器""" def __init__(self, n): """ :param n: int, 指明生成数列的前n个数 """ self.n = n # current用
汪凡
2018/05/29
6990
Python中的 生成器、迭代器
上一次输出的结果为下一次输入的初始值,重复的过程称为迭代,每次重复即一次迭代,并且每次迭代的结果是下一次迭代的初始值
用户7886150
2020/11/30
1.3K0
一文搞懂Python迭代器(通俗易懂)
python迭代器是一个相对难以理解的概念,Up在初次接触时也觉得晦涩。本文尽可能用通俗易懂的语言和例子,解释清楚python迭代器。
蜘蛛侠在写码
2024/11/30
1470
Python生成器
利用迭代器,我们可以在每次迭代获取数据(通过 next() 方法)时按照特定的规律进行生成。但是我们在实现一个迭代器时,关于当前迭代到的状态需要我们自己记录,进而才能根据当前状态生成下一个数据。为了达到记录当前状态,并配合 next() 函数进行迭代使用,我们可以采用更简便的语法,即 生成器(generator)。
ZackSock
2021/04/13
6620
一起学Python:迭代器
迭代器 迭代是访问集合元素的一种方式。迭代器是一个可以记住遍历的位置的对象。迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。 1. 可迭代对象 我们已经知道可以对list、tuple、str等类型的数据使用for...in...的循环语法从其中依次拿到数据进行使用,我们把这样的过程称为遍历,也叫迭代。 但是,是否所有的数据类型都可以放到for...in...的语句中,然后让for...in...每次从中取出一条数据供我们使用,即供我们迭代吗? 我们自定义了一个容
企鹅号小编
2018/02/26
5870
一起学Python:迭代器
迭代器执行流程
迭代器的执行流程,以及说明可迭代对象不一定是迭代器,但迭代器一定是可迭代对象 实例1 from collections import Iterable, Iterator import time class Classmate(object): """可迭代的对象(必须存在__iter__)""" def __init__(self): self.names = list() def add(self, name): self.names.app
py3study
2020/01/17
4570
Python自学成才之路 迭代器的使用
可迭代对象 实现了__iter__魔术方法的对象是可迭代对象(Iterable)
我是李超人
2020/08/26
3880
来看看Python迭代器能让你的代码提升100倍的密码
迭代器是一个实现了迭代器协议的对象。迭代器协议规定了一个对象必须实现两个方法:iter() 和 next()。然而,需要注意的是,从严格意义上讲,一个迭代器对象只需要实现 next() 方法,因为 iter() 函数(用于获取迭代器)会自动调用对象的 iter() 方法(如果该方法存在),而该方法通常返回对象自身。因此,在实际应用中,我们通常将只实现了 next() 方法的对象称为迭代器。
小白的大数据之旅
2024/11/20
980
Python 生成器 - generator
要创建一个生成器,有很多种方法。第一种方法很简单,只要把一个列表生成式的 [ ] 改成 ( )
Devops海洋的渔夫
2019/06/02
3740
python之(__next__和__iter__实现迭代器协议)
参考链接: Python __iter __()和__next __()| 将对象转换为迭代器
用户7886150
2020/11/30
1.5K0
Python全栈开发之并发编程
就是操作系统可以同时运行多个任务,就是可以一边用浏览器上网,同时又可以听歌,还能再撩个×××姐,这就是多任务,操作系统会轮流把系统调度到每个核心上去执行
py3study
2020/01/06
7270
面试题-python 什么是迭代器?
python 里面有 3 大神器:迭代器,生成器,装饰器。在了解迭代器之前,需弄清楚2个概念: 1.什么是迭代 2.什么是可迭代对象
上海-悠悠
2021/03/03
7540
探索Python中的迭代器(Iterator)和可迭代对象(Iterable)
在Python编程中,迭代器(Iterator)和可迭代对象(Iterable)是两个重要的概念。它们为我们提供了一种简洁而有效的方式来处理数据集合,同时也是深入理解Python语言内部机制的关键。本文将深入探讨迭代器和可迭代对象的概念、工作原理以及在实际代码中的应用。
疯狂的KK
2023/10/08
5330
探索Python中的迭代器(Iterator)和可迭代对象(Iterable)
相关推荐
Python 迭代器 - Iterable对象
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档