python - 检测迭代器是否会被消耗

标签 python

是否有一种统一的方法来了解迭代是否会消耗可迭代对象?

假设您有一个特定的函数crunch,它要求一个可迭代对象作为参数,并多次使用它。像这样的东西:

def crunch (vals):

    for v in vals:
        chomp(v)

    for v in vals:
        yum(v)

(注意:将两个 for 循环合并在一起不是一种选择)。

如果使用不是列表的可迭代对象调用函数,则会出现问题。在下面的调用中,永远不会执行 yum 函数:

crunch(iter(range(4))

我们原则上可以通过重新定义 crunch 函数来解决这个问题,如下所示:

def crunch (vals):
    vals = list(vals)

    for v in vals:
        chomp(v)

    for v in vals:
        yum(v)

但是如果对 crunch 的调用是这样的话,这将导致使用两倍的内存:

hugeList = list(longDataStream)
crunch(hugeList)

我们可以通过像这样定义 crunch 来解决这个问题:

def crunch (vals):
    if type(vals) is not list:
        vals = list(vals)

    for v in vals:
        chomp(v)

    for v in vals:
        yum(v)

但仍然存在调用代码将数据存储在某些地方的情况

  • 不能食用
  • 不是列表

例如:

from collections import deque
hugeDeque = deque(longDataStream)
crunch(hugeDeque)

最好有一个 isconsumable 谓词,这样我们就可以像这样定义 crunch:

def crunch (vals):
    if isconsumable(vals):
        vals = list(vals)

    for v in vals:
        chomp(v)

    for v in vals:
        yum(v)

这个问题有解决方案吗?

最佳答案

一种可能性是使用 isinstance(val, collections.Sequence) 来测试该项目是否是序列。非消耗性仍然不能完全保证,但我认为这是你能得到的最好的。 Python 序列必须有一个长度,这意味着至少它不能是一个开放式迭代器,并且通常意味着必须提前知道元素,这反过来又意味着它们可以被迭代不消耗它们。仍然可以编写符合序列协议(protocol)但不可重复的病态类,但您永远无法处理这些类。

请注意,IterableIterator 都不是合适的选择,因为这些类型不保证长度,因此甚至不能保证迭代会是有限的,更不用说可重复的了。但是,您可以检查 SizedIterable

重要的是记录您的函数将迭代其参数两次,从而警告用户他们必须传入支持此功能的对象。

关于python - 检测迭代器是否会被消耗,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15379994/

相关文章:

Python Tkinter,简单示例在 win 7 上失败

python - 如何消除数据中的急剧跳跃?

python - 描述文件的 python pickleable 对象的设计

python - python 中的selenium - 一次超时会导致所有后续请求超时

Python os.list_dir 停止一级短

python - 使用 scipy.optimise.minimise() 执行同时拟合/最小化

python - PyMysql 使用全局游标更新函数内的查询

Python:将 n 元组转换为 x 元组,其中 x < n

python - 如何以普通文本形式接收 html 电子邮件?

python - groupby 和 mean 之后的 "No numeric types to aggregate"