Python 中的迭代器

Python 中的迭代器

  • [Python 中的迭代器](#Python 中的迭代器)

Python 中的迭代器

迭代是用于数据处理和数据转换的关键工具之一。当处理大型数据集以及不可能或不能高效地将整个数据集带入内存时,迭代尤其有用。迭代器提供了一种将数据一次一项地带入内存的方法。

创建迭代器的方法是用一个单独的类定义迭代器,并实现 __iter____next__ 等特殊方法。但还有一种使用 yield 操作创建迭代器的新方法,即生成器。接下来,我们将首先学习迭代器。讲完迭代器后再讲生成器。

迭代器是用来迭代其他对象的对象。迭代器可以迭代的对象称为可迭代对象。理论上,这两个对象是不同的,但可以在可迭代对象类中实现迭代器。这虽然在技术上是可行的,但不建议这样做(稍后会讲到原因)。我们将通过一个例子来讨论为什么这种方法不是一种好的设计方法。在下面的代码片段,是在 Python 中使用 for 循环进行迭代的示例:

python 复制代码
#例一:在一个列表上迭代
for x in [1, 2, 3]:
  print(x)

#例二:在一个字符串上迭代
for x in "Hello, world":
  print(x, end="")
print(' ')

#例三:在一个字典上迭代
week_days = {1: '星期一', 2: '星期二', 3: '星期三', 4: '星期四', 5: '星期五', 6: '星期六', 7: '星期日'}
for key in week_days:
  print(key, week_days[key])

#例四:在一个文件上迭代,输出文件的每一行
for row in open('abc.txt'):
  print(row, end=""

在这些代码示例中,我们使用了不同的 for 循环来遍历列表、字符串、字典和文件(Python 默认所有的集合都是可迭代的)。所有这些数据类型都是可迭代的,因此我们可以使用简单的 for 循环语法来遍历这些集合或序列中的项目。接下来,我们将学习使对象具有可迭代性的因素,这也被称为迭代器协议

在 Python 中,迭代器对象必须实现两个特殊方法:__iter____next__。要迭代一个对象,该对象必须至少实现__iter__方法。一旦一个对象实现了__iter__方法,我们就称其是可迭代的。下面将介绍这些方法:

  • __iter__:这个方法返回一个迭代器对象。循环开始时调用这个方法,以获取迭代器对象;
  • __next__:在循环的每次迭代中调用这个方法,它返回可迭代对象中的下一个项目。

为了解释如何构建可迭代的自定义对象,我们将实现星期类类,该类将所有工作日的数字和名称存储在字典中。默认情况下,此类不可迭代。为了使其可迭代,我们给它添加了__iter__方法。为了保持示例简单,我们还给它添加了__next__方法。以下是包含星期类类和主程序的代码,该程序会迭代以获取工作日的名称:

python 复制代码
class 星期类:
    def __init__(我):
        我.星期字典 = {1: '星期一', 2: '星期二', 3: '星期三', 4: '星期四', 5: '星期五', 6: '星期六', 7: '星期日'}
        我._索引 = 1

    def __iter__(我):
        我._索引 =  1
        return 我

    def __next__(我):
        if 我._索引 < 1 | 我._索引 > 7:
            raise StopIteration
        else:
            ret_value = 我.星期字典[我._索引]
            我._索引 += 1
        return ret_value

if __name__ == '__main__':
    星期 = 星期类()
    for 天 in 星期:
        print(天)

以上代码的输出结果是:

星期一
星期二
星期三
星期四
星期五
星期六
星期日

这个代码示例只是为了演示如何在同一对象类中实现__iter____next__方法。这种实现迭代器的风格在互联网上很常见,但它不是推荐的方法,并且被认为是一种糟糕的设计。原因是,当我们在for循环中使用它时,我们会将主对象作为迭代器返回,因为我们在同一个类中实现了__iter___next__。这可能会产生不可预测的结果。以下代码片段演示了这一点:

python 复制代码
#星期类的定义在上面
if __name__ == '__main__':
    星期 = 星期类()

    迭代1 = iter(星期)
    迭代2 = iter(星期)

    print(迭代1.__next__())
    print(迭代2.__next__())
    print(next(迭代1))
    print(next(迭代2))

以上代码的输出结果是:

星期一
星期二
星期三
星期四

在这个例子中,我们用两个不同的迭代器迭代同一个星期对象。这个程序的输出结果不是我们想要的。这是因为两个迭代器共用了一个_索引属性。在这段代码中,没有使用 for 循环,而是使用iter函数为星期类类的对象星期创建了两个迭代器对象。iter函数是一个Python标准函数,它调用__iter__方法。为了获取可迭代对象中的下一个项,我们直接使用__next__方法和next函数。next函数也是一个标准函数。使用可迭代对象作为迭代器的这种方法也不被认为是线程安全的。

最好的方法是使用单独的迭代器类,并通过__iter__方法创建迭代器的新实例。每个迭代器实例都必须管理自己的内部状态。下面是星期类类相同代码示例的修改版本,其中包含一个单独的迭代器类:

python 复制代码
class 星期类:
    def __init__(我):
        我.星期字典 = {1: '星期一', 2: '星期二', 3: '星期三', 4: '星期四', 5: '星期五', 6: '星期六', 7: '星期日'}
        我._索引 = 1

    def __iter__(我):
         return 星期迭代器类(我.星期字典)


class 星期迭代器类:
    def __init__(我, 星期字典引用):
        我.星期字典引用 = 星期字典引用
        我._索引  = 1

    def __next__(我):
        if 我._索引 < 1 | 我._索引 > 7:
            raise StopIteration
        else:
            ret_value = 我.星期字典引用[我._索引]
            我._索引 += 1
        return ret_value


if __name__ == '__main__':
    星期 = 星期类()

    迭代1 = iter(星期)
    迭代2 = iter(星期)

    print(迭代1.__next__())
    print(迭代2.__next__())
    print(next(迭代1))
    print(next(迭代2))

这个代码输出结果是:

星期一
星期一
星期二
星期二

可以看到,通过定义一个单独的星期迭代器类迭代1迭代2 这两个迭代器都单独保存了自己的状态,输出结果符合我们的预期。

<完>

相关推荐
Ven%几秒前
如何修改pip全局缓存位置和全局安装包存放路径
人工智能·python·深度学习·缓存·自然语言处理·pip
枫欢2 分钟前
将现有环境192.168.1.100中的svn迁移至新服务器192.168.1.4;
服务器·python·svn
HEU_firejef2 分钟前
Redis——缓存预热+缓存雪崩+缓存击穿+缓存穿透
数据库·redis·缓存
测试杂货铺28 分钟前
UI自动化测试实战实例
自动化测试·软件测试·python·selenium·测试工具·测试用例·pytest
soragui34 分钟前
【ChatGPT】OpenAI 如何使用流模式进行回答
linux·运维·游戏
KELLENSHAW1 小时前
MySQL45讲 第三十七讲 什么时候会使用内部临时表?——阅读总结
数据库·mysql
余~~185381628001 小时前
NFC 碰一碰发视频源码搭建技术详解,支持OEM
开发语言·人工智能·python·音视频
苏三有春1 小时前
PyQt实战——使用python提取JSON数据(十)
python·json·pyqt
白云coy1 小时前
Redis 安装部署[主从、哨兵、集群](linux版)
linux·redis