是否有一种统一的方法来了解迭代是否会消耗可迭代对象?
假设您有一个特定的函数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)但不可重复的病态类,但您永远无法处理这些类。
请注意,Iterable
和 Iterator
都不是合适的选择,因为这些类型不保证长度,因此甚至不能保证迭代会是有限的,更不用说可重复的了。但是,您可以检查 Sized
和 Iterable
。
重要的是记录您的函数将迭代其参数两次,从而警告用户他们必须传入支持此功能的对象。
关于python - 检测迭代器是否会被消耗,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15379994/