迭代器的实际应用场景是什么?

10 天前
 codists

概述

最近在梳理 iterator ,不得不说, 即使自己写了很多年的代码,我仍然没有在实际应用中看到自定义的迭代器。即使读了很多书,但是这些书中的示例大多是滥竽充数,不具备实际应用意义。所以顺着网线爬上 V 站请教各位。

可迭代对象 & 迭代器定义

可迭代对象

如果一个对象定义了 __iter__() 方法或定义了 __getitem__() 方法,那么这样的对象称为可迭代对象(iterable)。

迭代器

如果一个对象定义了 __iter__() 方法和 __next__() 方法,那么这样的对象称为迭代器(iterator)。

1.后续的讨论都是基于以上两个定义。

2.因迭代器常和可迭代对象结合使用,故引如可迭代对象这一概念,但迭代器的概念先于生成器(generator),在后续的讨论中请勿涉及生成器。

一些示例

示例 1

python 3 的 range() 是一个可迭代对象,其实现使用了迭代器。使用迭代器后不是直接生成列表,节省了内存,体现了迭代器的应用意义。

示例 2

《 Learn Python Programming(4th)》 第 246 页:

class OddEven:
    def __init__(self, data):
        self._data = data
        self.indexes = list(range(0, len(data), 2)) + list(range(1, len(data), 2))

    def __iter__(self):
        return self

    def __next__(self):
        if self.indexes:
            return self._data[self.indexes.pop(0)]
        raise StopIteration


# Testing the OddEven class
oddeven = OddEven("0123456789")
print("".join(c for c in oddeven))  # 0246813579

oddeven = OddEven("ABCD")  # or manually...
it = iter(oddeven)  # this calls oddeven.__iter__ internally
print(next(it))  # A
print(next(it))  # C
print(next(it))  # B
print(next(it))  # D

该示例虽然创建了一个迭代器,但就功能而言其实就是“将奇数位置的字符放在前半段,将偶数位置的字符放在后半段”,完全没有必要使用迭代器。关于迭代器的实力,本人看到的大多是这样的——毫无实际应用意义,令人深恶痛绝!

问题

问题 1

PEP 234 中写到 iterator 的 virtues 有:

  1. It provides an extensible iterator interface.
  2. It allows performance enhancements to list iteration.
  3. It allows big performance enhancements to dictionary iteration.
  4. It allows one to provide an interface for just iteration without pretending to provide random access to elements.
  5. It is backward-compatible with all existing user-defined classes and extension objects that emulate sequences and mappings, even mappings that only implement a subset of {__getitem__, keys, values, items}.
  6. It makes code iterating over non-sequence collections more concise and readable.

中译版:

如果包含该提案的所有部分,则会以一致且灵活的方式解决许多问题。其主要优点包括以下四点——不,五点——不,六点

  1. 它提供了一个可扩展的迭代器接口。
  2. 它允许对列表迭代进行性能优化。
  3. 它允许对字典迭代进行大幅度性能提升。
  4. 它允许为仅迭代提供接口,而无需假装提供对元素的随机访问。
  5. 它与所有现有的用户定义类和模拟序列和映射的扩展对象向后兼容,即使是仅实现了 {__getitem__, keys, values, items} 子集的映射。
  6. 它使遍历非序列集合的代码更加简洁易读。

上面所列出的优点较抽象,各位能否提供一些具体的例子?

问题 2

各位在实际应用中是否自己实现过迭代器?如果有麻烦提供一些例子。

参考资料

[1] Python Document Glossary ,iterator: https://docs.python.org/3/glossary.html#term-iterator

[2] PEP 234 – Iterators: https://peps.python.org/pep-0234

[3] PEP 234 – 迭代器: https://peps.pythonlang.cn/pep-0234/

2398 次点击
所在节点    Python
32 条回复
Livid
10 天前
@craftsmanship 谢谢,1 楼的账号已经被彻底 ban 。
y1y1
10 天前
@aloxaf #17 毕竟工作八年,那很牛了
realpg
10 天前
@codists #16

99%的码农自己写的迭代器, 都是因为上下游接口要求你传递过去的东西必须是可迭代的...

具体就根据上下游的要求来了
BingoW
9 天前
生产者消费者模式?手搓一个消息队列?
orioleq
9 天前
你要写迭代器的论文非得找个实践的例子?自定义迭代器__iter__是基本数据结构用的,实际用的话一般都是基于基本结构写 yield 生成器函数
Shazoo
9 天前
如果你需要处理所有的迭代器返回值,那迭代器就是节约了一些资源的负载峰值。
如果你未必需要处理所有迭代器返回值,只是顺序查找某个合适的返回值,那迭代器节约了大量的资源。

好比,你做个跳舞链来做精确覆盖。那肯定用迭代器。陆续返回客户所需要的解,让用户去判断是否继续查找解。
fortytwo
9 天前
有时候写爬虫,需要翻页,我就用迭代器。函数内部判断需不需要翻页,能够一定程度上提升可读性,写起来也方便。有点语法糖的意思。
tangkaidu
9 天前
我主要省内存吧 我们原来修一些数据 bug 十几亿数据读出来 原来不知道怎么处理 一会脚本挂了 又搞什么内存提高使用 监控 cpu 啥的 后来用迭代器 内存不增长
kzfile
9 天前
我要处理的数据量很大,单个数据也很大,不想先生成都放到内存里,用迭代器模拟数组,可以无缝嵌入现有的逻辑
WithoutSugarMiao
9 天前
兄弟,你是没用过 async await 吗?
WithoutSugarMiao
9 天前
@WithoutSugarMiao 就算你是学生没用过 async await 。那你刷 leetcode 没用过 range 吗?如果你是竞赛生你刷 codeforce 没用过迭代器递归转迭代吗?
julyclyde
4 天前
@WithoutSugarMiao 和 async/await 有啥关系? iterator 不是很古代的时候就已经有了吗?

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://ex.noerr.eu.org/t/1165216

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX