有没有一种统一的方法可以知道迭代是否会消耗iterable对象?在
假设您有一个函数crunch
,它请求一个iterable对象作为参数,并多次使用它。比如:
def crunch (vals):
for v in vals:
chomp(v)
for v in vals:
yum(v)
(注意:合并两个for
循环不是一个选项)。在
如果使用不是列表的iterable调用函数,则会出现问题。在下面的调用中,yum
函数从不执行:
原则上,我们可以通过如下重新定义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)
这个问题有解决办法吗?在
另一个附加选项是查询iterable是否是它自己的迭代器:
因为在本例中,它只是一个迭代器。在
这适用于生成器、迭代器、文件和许多其他为“一次运行”而设计的对象,换句话说,所有iterable本身就是迭代器,因为iterator returns ^{} from its ^{} 。在
但这可能还不够,因为有些对象在迭代时会清空自己,而不是自己的迭代器。在
通常,一个自消费对象将是它自己的迭代器,但在某些情况下这可能是不允许的。在
假设有一个类包装了一个列表并在迭代时清空这个列表,比如
^{pr2}$你叫它什么
如果我现在向该列表中添加额外的数据并再次迭代相同的对象,我将得到新的数据,即breach of the protocol:
因此,在这种情况下,对象必须返回一个与自身不同的迭代器,尽管它是自消耗的。在这种情况下,可以用
它在每次迭代中都返回一个新的生成器—在我们讨论的案例中,这个生成器可能会失败。在
一种可能是使用
isinstance(val, collections.Sequence)
测试该项是否为序列。非消耗性仍然不能完全保证,但我认为这是你能得到的最好的。Python序列必须有一个长度,这意味着至少它不能是一个开放的迭代器,并且通常意味着必须提前知道元素,这反过来意味着可以在不消耗元素的情况下迭代它们。仍然可以编写符合序列协议但不可编辑的病理类,但您永远无法处理这些类。在注意,}都不是合适的选择,因为这些类型不能保证长度,因此不能保证迭代是有限的,更不用说可重复了。但是,您可以同时检查}。在
Iterable
和{Sized
和{重要的是要记录下你的函数将迭代它的参数两次,从而警告用户他们必须传入一个支持此操作的对象。在
在这种情况下,}的完整性,因为一个迭代器在另一个迭代器启动之前完成
tee
将在内部存储{相关问题 更多 >
编程相关推荐