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 这两个迭代器都单独保存了自己的状态,输出结果符合我们的预期。

<完>

相关推荐
这个DBA有点耶7 小时前
NULL不是空——数据库里最反直觉的设计,90%新人踩过的坑
数据库·mysql·代码规范
用户8356290780517 小时前
Python 实现 PDF 文件加密与解密方法
后端·python
用户8356290780517 小时前
使用 Python 冻结与拆分 Excel 窗格教程
后端·python
这个DBA有点耶9 小时前
AI写的SQL跑崩了生产库,这锅谁背?
数据库·人工智能·程序员
镜舟科技10 小时前
Databricks 再提 LTAP,AI 时代的数据底座为何重回大一统叙事?
数据库·架构·agent
Databend11 小时前
从湖仓升级为 Agent 时代的数据控制面,Snowflake 和 Databricks 有哪些布局
大数据·数据库·agent
ClouGence14 小时前
SQL Server CDC 能放到 Always On 备库读吗?一文讲透原理与实践
数据库·sql server
你好潘先生16 小时前
别再记命令了,用 yeero do 说句人话就能跑脚本,而且不烧 token
服务器·python·命令行
Agent_大师16 小时前
WebSocket 行情重连成功,K线缺口不会自动消失
python
荣码16 小时前
LLM结构化输出:让AI返回JSON而不是废话,我踩了4个坑
java·python