【从零学习python 】59.迭代器:优化数据遍历的高效工具

迭代器

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

1. 可迭代对象

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

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

for i in 100:
    print(i)

上述代码会报错 TypeError: 'int' object is not iterable,即整型 int 不是 iterable,即整型不是可以迭代的。

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

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

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

from collections import Iterable

print(isinstance([], Iterable))  # True
print(isinstance({}, Iterable))  # True
print(isinstance('abc', Iterable))  # True
print(isinstance(mylist, Iterable))  # False
print(isinstance(100, Iterable))  # False

3. 可迭代对象的本质

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

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

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

一个具备了 __iter__ 方法的对象,就是一个可迭代对象。

from collections.abc import Iterable

class Demo(object):
    def __init__(self, n):
        self.n = n
        self.current = 0
    def __iter__(self):
        pass

demo = Demo(10)
print(isinstance(demo, Iterable))  # True

for d in demo:  # 重写了 `__iter__` 方法以后,demo 就是一个一个可迭代对象了,可以放在 `for...in` 的后面
    print(d)

# 此时再使用 `for...in` 循环遍历,会提示 `TypeError: iter() returned non-iterator of type 'NoneType'`
# 这是因为,一个可迭代对象如果想要被 `for...in` 循环,它必须要有一个迭代器

4. 迭代器(Iterator)

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

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

class MyIterator(object):
    def __init__(self, n):
        self.n = n
        self.current = 0

    # 自定义迭代器需要重写 `__iter__` 和 `__next__` 方法
    def __iter__(self):
        return self

    def __next__(self):
        if self.current < self.n:
            value = self.current
            self.current += 1
            return value
        else:
            raise StopIteration

my_it = MyIterator(10)

for i in my_it:  # 迭代器重写了 `__iter__` 方法,它本身也是一个可迭代对象
    print(i)

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

调用一个对象的 __iter__ 方法,或者调用 iter() 内置函数,可以获取到一个可迭代对象的迭代器。

names = ['hello', 'good', 'yes']
print(names.__iter__())  # 调用对象的 `__iter__()` 方法
print(iter(names))  # 调用 `iter()` 内置函数

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

from collections.abc import Iterator
names = ['hello', 'good', 'yes']
print(isinstance(iter(names), Iterator))

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

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

7. 迭代器的应用场景

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

举个例子,比如,数学中有个著名的斐波数列(Fibonacci sequence),每个数字是前两个数字之和。如果我们要生成斐波那契数列的前n个数字并进行迭代,使用迭代器就非常方便。

class FibonacciIterator:
    def __init__(self, n):
        self.n = n
        self.current = 0
        self.a = 0
        self.b = 1

    def __iter__(self):
        return self

    def __next__(self):
        if self.current < self.n:
            value = self.a
            self.a, self.b = self.b, self.a + self.b
            self.current += 1
            return value
        else:
            raise StopIteration

fib_iter = FibonacciIterator(10)

for num in fib_iter:
    print(num)

上述代码中,定义了一个斐波那契数列迭代器 FibonacciIterator,根据提供的数量 n,每次迭代返回斐波那契数列中的下一个数字。我们可以通过 for...in... 循环来遍历迭代器并打印每个数字。

迭代器还有其他许多应用场景,例如处理大型数据集时,可以使用迭代器逐行读取文件而不需要一次性将整个文件加载到内存中;在生成器函数中,yield语句可以用于构建迭代器,以节省内存等。总之,迭代器提供了一种高效、节省资源的迭代方式,使得我们可以逐个访问并处理数据,而无需事先生成或存储整个数据集合。

进阶案例

【Python】Python 实现猜单词游戏——挑战你的智力和运气!

【python】Python tkinter库实现重量单位转换器的GUI程序

【python】使用Selenium获取(2023博客之星)的参赛文章

【python】使用Selenium和Chrome WebDriver来获取 【腾讯云 Cloud Studio 实战训练营】中的文章信息

使用腾讯云 Cloud studio 实现调度百度AI实现文字识别

【玩转Python系列【小白必看】Python多线程爬虫:下载表情包网站的图片

【玩转Python系列】【小白必看】使用Python爬取双色球历史数据并可视化分析

【玩转python系列】【小白必看】使用Python爬虫技术获取代理IP并保存到文件中

【小白必看】Python图片合成示例之使用PIL库实现多张图片按行列合成

【小白必看】Python爬虫实战之批量下载女神图片并保存到本地

【小白必看】Python词云生成器详细解析及代码实现

【小白必看】Python爬取NBA球员数据示例

【小白必看】使用Python爬取喜马拉雅音频并保存的示例代码

【小白必看】使用Python批量下载英雄联盟皮肤图片的技术实现

【小白必看】Python爬虫数据处理与可视化

【小白必看】轻松获取王者荣耀英雄皮肤图片的Python爬虫程序

【小白必看】利用Python生成个性化名单Word文档

【小白必看】Python爬虫实战:获取阴阳师网站图片并自动保存

小白必看系列之图书管理系统-登录和注册功能示例代码

小白实战100案例: 完整简单的双色球彩票中奖判断程序,适合小白入门

使用 geopandas 和 shapely(.shp) 进行地理空间数据处理和可视化

使用selenium爬取猫眼电影榜单数据

图像增强算法Retinex原理与实现详解

爬虫入门指南(8): 编写天气数据爬虫程序,实现可视化分析

爬虫入门指南(7):使用Selenium和BeautifulSoup爬取豆瓣电影Top250实例讲解【爬虫小白必看】

爬虫入门指南(6):反爬虫与高级技巧:IP代理、User-Agent伪装、Cookie绕过登录验证及验证码识别工具

爬虫入门指南(5): 分布式爬虫与并发控制 【提高爬取效率与请求合理性控制的实现方法】

爬虫入门指南(4): 使用Selenium和API爬取动态网页的最佳方法

爬虫入门指南(3):Python网络请求及常见反爬虫策略应对方法

爬虫入门指南(2):如何使用正则表达式进行数据提取和处理

爬虫入门指南(1):学习爬虫的基础知识和技巧

深度学习模型在图像识别中的应用:CIFAR-10数据集实践与准确率分析

Python面向对象编程基础知识和示例代码

MySQL 数据库操作指南:学习如何使用 Python 进行增删改查操作

Python文件操作指南:编码、读取、写入和异常处理

使用Python和Selenium自动化爬取 #【端午特别征文】 探索技术极致,未来因你出“粽” # 的投稿文章

Python多线程与多进程教程:全面解析、代码案例与优化技巧

Selenium自动化工具集 - 完整指南和使用教程

Python网络爬虫基础进阶到实战教程

Python入门教程:掌握for循环、while循环、字符串操作、文件读写与异常处理等基础知识

Pandas数据处理与分析教程:从基础到实战

Python 中常用的数据类型及相关操作详解

【2023年最新】提高分类模型指标的六大方案详解

Python编程入门基础及高级技能、Web开发、数据分析和机器学习与人工智能

用4种回归方法绘制预测结果图表:向量回归、随机森林回归、线性回归、K-最近邻回归

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

全栈若城

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值