Python可迭代对象与迭代器的用法及说明

 更新时间:2026年04月08日 09:17:45   作者:掐死你滴温柔  
文章主要介绍了迭代器和可迭代对象的概念、Python中如何判断一个对象是否可迭代、序列为什么可迭代、如何使用iter()函数处理可调用对象、Python中迭代器的接口以及Sentence类的迭代器实现

迭代是数据处理的基石:程序将计算应用于数据序列。如果数据太大,在内存中放不下,则需要采用“惰性”的方式获取数据,即只按需获取和处理数据项的一部分,而不是一次性加载整个数据集。这就是迭代器的作用。

在Python中,所有容器类型都是可迭代对象。Python使用可迭代对象提供的迭代器支持以下操作:

  • for循环
  • 列表,字典,集合推导式
  • 拆包赋值
  • 构造容器实例

单词序列

首先我们通过下面代码开启可迭代对象之旅。

import re
import reprlib

RE_WORD = re.compile(r'\w+')


class Sentence:
    def __init__(self, text: str):
        self.text = text
        self.words = RE_WORD.findall(text)

    def __len__(self):
        return len(self.words)

    def __getitem__(self, index):
        return self.words[index]

    def __repr__(self):
        # reprlib.repr这个实用函数用于生成大型模型结构的简略字符串表现形式
        return f"Sentence({reprlib.repr(self.text)})"

我们测试一下上面的代码:

s = Sentence(text="静夜思:唐【李白】 床前明月光,疑是地上霜。举头望明月,低头思故乡。")
print(s)   # 输出:Sentence('静夜思:唐【李白】 床前...。举头望明月,低头思故乡。')
for i in s:
    print(i)
print(s[0]) # 静夜思
print(s[-1]) # 低头思故乡
print(list(s))  # 输出:['静夜思', '唐', '李白', '床前明月光', '疑是地上霜', '举头望明月', '低头思故乡']

上面代码中传入一个字符串,创建一个Sentence实例。reprlib.repr函数默认情况下生成的字符串最多有30个字符,所以多余的字符串使用...替代。Sentence实例可以迭代,因为可以迭代,使用Sentence对象可用于构建列表和其他可迭代类型。

Python开发者都知道,序列可以迭代,为什么呢?

序列可以迭代的原因:iter函数

需要迭代对象x时,Python会自动调用iter(x)。

内置函数iter执行以下操作:

  • 检查对象是否实现了__iter__方法,如果实现了就调用它,获取一个迭代器。
  • 如果没有实现__iter__方法,但是实现了__getitem__方法,那么iter()创建一个迭代器,尝试索引(从0开始)获取项。
  • 然后尝试失败,则Python抛出TypeError异常,通常会提示“'C' object is not iterable”,其中C是目标对象所属的类。

所有Python序列可迭代的原因是,按照定义,序列都实现了__getitem__方法。其实,标准的序列也都实现了__iter__方法。因此不仅实现了特殊方法__iter__的对象被视为可迭代对象,实现了__getitem__方法的对象也被视为可迭代对象。

from collections import abc
class Demo:
    def __getitem__(self, item):
        pass

class Demo1:
    def __iter__(self):
        pass

print(iter(Demo()))  # <iterator object at 0x000001E61560C610>
print(isinstance(Demo1(),abc.Iterable)) #True

值得一提的是,在Python3.10开始,检查对象x是否迭代,最准确的方法是使用iter(x)函数,如果不可迭代,则处理TypeError异常。这比isinstence(x,abc.Iterable)更准确,因为iter(x)函数还会考虑过时的__getitem__方法,而抽象基类Iterable则不考虑。

内置的iter()更常被Python自身使用,我们自己很少用到。iter()函数还有另一种用法,不过鲜为人知。

使用iter处理可调用对象

调用iter()时,传入两个参数可以为函数或任何可迭代对象创建迭代器。对于这种用法,第一个参数必须是一个可迭代对象,重复调用产生值;第二个参数是哨符,即一种标记值,如果可调用对象返回哨符,则迭代器抛出StopIteration,而不产出哨符。

例如下面示例:使用iter函数掷一个6面骰子,直到点数为1.

import random

def d6():
    return random.randint(1, 6)

d6_iter = iter(d6, 1)
print(d6_iter)
for i in d6_iter:
    print(i)
输出:
<callable_iterator object at 0x0000016A13F82C80>
4
3
5
6
2
5
3
2
4

上面的iter函数返回的是一个callable_iterator。这个示例中的for循环可能会运行很长时间,但是绝对不会产生1,因为1是哨符。

可迭代对象和迭代器

由上面内容可知,可迭代对象:使用内置函数iter可以获取迭代器的对象。如果对象实现了能返回迭代器的__iter__方法,那么对象就是可迭代的。序列都可以迭代。实现了__getitem__方法,而且接受从0开始的索引,这种对象也可以迭代。

可迭代对象和迭代器之间的关系是:Python从可迭代对象中获取迭代器。

Python中字符串是可以迭代的。表面上看不出来,但是背后有一个迭代器。

s = 'ABC'
for char in s:
    print(char)

假如没有for语句,我们不得不使用while循环模拟:

s='ABC'
s_iter = iter(s)
while True:
    try:
        print(next(s_iter))
    except StopIteration:
        del s_iter # 释放s_iter的引用,即废弃迭代器对象
        break

StopIteration表明迭代器已耗尽。内置函数iter()在内部自行处理for循环和其他迭代上下文(列表推导式,可迭代对象拆包等)的StopIteration异常。

Python标准的迭代器接口有以下两个方法:

  • __next__:返回序列的下一项,如果没有项了,抛出StopIteration异常
  • __iter__:返回self,以便在预期可迭代对象的地方使用迭代器。例如for循环中

回到上面的Sentence类:

s = Sentence(text="静夜思:唐【李白】 床前明月光,疑是地上霜。举头望明月,低头思故乡。")
it = iter(s)
print(it)  # <iterator object at 0x0000026DBBCD3460>
print(next(it))  # 静夜思
print(next(it))  # 唐
print(list(it))  # ['李白', '床前明月光', '疑是地上霜', '举头望明月', '低头思故乡']

可以清楚的看出iter()是如何构建迭代器的,以及next()是如何使用迭代器的,以及无法重置已经耗尽的迭代器。

为Sentence类实现__iter__方法

下面实现经典迭代器设计模式。虽然不符合Python的习惯做法,后续会重构。但是通过下面代码,可以明确可迭代容器和迭代器之间的关系。

import re
import reprlib

RE_WORD = re.compile(r'\w+')


class Sentence:
    def __init__(self, text: str):
        self.text = text
        self.words = RE_WORD.findall(text)

    def __len__(self):
        return len(self.words)

    def __repr__(self):
        # reprlib.repr这个实用函数用于生成大型模型结构的简略字符串表现形式
        return f"Sentence({reprlib.repr(self.text)})"

    def __iter__(self):
        return SentenceIterator(self.words)


class SentenceIterator:
    def __init__(self, words):
        self.words = words
        self.index = 0

    def __next__(self):
        try:
            word = self.words[self.index]
        except IndexError:
            raise StopIteration()
        self.index += 1
        return word

    def __iter__(self):
        return self

与前一版相比,这里只多了一个__iter__方法,没有了__getitem__方法,为的是明确表明这个类之所以可以迭代,是因为实现了__iter__方法。根据可迭代协议,__iter__方法实例化并返回一个迭代器(SentenceIterator)。

注意:对于上面的SentenceIterator迭代器示例来说,没必要在类中实现__iter__方法,不过这样做是对的,因为迭代器应该实现__iter__和__next__这两个方法,而且这样做能让迭代器通过issubclass(SentenceIterator,abc.Iterator)测试。

不要把可迭代对象变成迭代器

构建可迭代对象和迭代器时经常会出现错误,原因是混淆了二者。要知道,可迭代对象有个__iter__方法,每次都实例化一个新的迭代器;而迭代器要实现__next__方法,返回单个元素,此外还要实现__iter__方法,返回本身。

因此迭代器是可迭代对象,但是可迭代对象不是迭代器。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • python用ConfigObj读写配置文件的实现代码

    python用ConfigObj读写配置文件的实现代码

    发现一个简单而又强大的读写配置文件的lib,个人觉得最大的亮点在于自带的格式校验功能,并且支持复杂的嵌套格式,而且使用起来也相当的简便
    2013-03-03
  • Python之PyUnit单元测试实例

    Python之PyUnit单元测试实例

    这篇文章主要介绍了Python之PyUnit单元测试实例,是非常实用的技巧,需要的朋友可以参考下
    2014-10-10
  • python实现去掉字符串中的\xa0、\t、\n

    python实现去掉字符串中的\xa0、\t、\n

    这篇文章主要介绍了python实现去掉字符串中的\xa0、\t、\n方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-08-08
  • Win10系统下Pytorch环境的搭建过程

    Win10系统下Pytorch环境的搭建过程

    今天给大家带来的是关于Python的相关知识,文章围绕着Win10系统Pytorch环境搭建过程展开,文中有非常详细的介绍及图文示例,需要的朋友可以参考下
    2021-06-06
  • Python中类的mro与继承关系详解

    Python中类的mro与继承关系详解

    这篇文章主要介绍了Python中类的mro与继承关系,文章围绕主题展开初步认识mro的解析顺序,具有一定的参考价值。需要的朋友可以参考一下
    2022-07-07
  • Python实现统计文本中字符的方法小结

    Python实现统计文本中字符的方法小结

    在计算机编程中,经常需要对文本数据进行处理和分析,字符统计是其中一个常见任务,本文将详细介绍如何使用Python进行字符统计,希望对大家有所帮助
    2024-01-01
  • Django bulk_create()、update()与数据库事务的效率对比分析

    Django bulk_create()、update()与数据库事务的效率对比分析

    这篇文章主要介绍了Django bulk_create()、update()与数据库事务的效率对比分析,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-05-05
  • pytorch使用nn.Moudle实现逻辑回归

    pytorch使用nn.Moudle实现逻辑回归

    这篇文章主要为大家详细介绍了pytorch使用nn.Moudle实现逻辑回归,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-07-07
  • Python中的正则表达式与JSON数据交换格式

    Python中的正则表达式与JSON数据交换格式

    正则表达式 是一个特殊的字符序列,一个字符串是否与我们所设定的这样的字符序列,相匹配快速检索文本、实现替换文本的操作。这篇文章主要介绍了Python中的正则表达式与JSON ,需要的朋友可以参考下
    2019-07-07
  • python具名元组(namedtuple)的具体使用

    python具名元组(namedtuple)的具体使用

    本文主要介绍了python具名元组(namedtuple)的具体使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-03-03

最新评论