2017-04-18 28 views
0

我只是偶然发现或多或少(回答this问题),人们可以至少一些迭代器使用copy.copy()复制(不发球)迭代器:这是一个功能或“实施细节”

Q复制:由于这在module documentation中根本没有提及,所以我想知道这是官方功能还是可能在不通知的情况下从语言中删除的内容。

补充问:请问itertools.tee存在的相同注意事项适用于此处吗?即可能会消耗大量内存,可能会更有效地创建列表。

这是为什么这在我看来,一个非常有用的功能的例子(尝试做同样与tee):

def triu_indices(n): 
    """indices into the upper triangle of a square matrix""" 
    yi = iter(range(n)) 
    for y in yi: 
     for x in copy.copy(yi): 
      yield y, x 

for y, x in triu_indices(4): 
    print(y, x) 

# 0 1 
# 0 2 
# 0 3 
# 1 2 
# 1 3 
# 2 3 

更新:我不好,我应该已经明确表示,这也适用于“适当的”迭代器(我测试了itertools.productitertools.combinations)不仅适用于“不是真的迭代器”range。它也适用于list迭代器。它确实不是使用文件(_io.TextIOWrapper)对象。

回答

1

如果没有记录,可能确实不能依赖它。也就是说,这种类型的功能似乎更容易记录下来,后来被删除。然而,你的例子只是复制一个特定类型的迭代器,即范围迭代器,并且你通常不应该期望能够复制任意迭代器。

使用您使用的范围迭代器,至少在当前实现中,没有像tee那样的开销类型。看起来copy正在使用pickle __reduce_ex__机制,这意味着复制范围迭代器本质上会创建一个新的范围迭代器对象,该对象应该与原始对象一样具有迭代效率。它不存储单个值。 (我可以瞬间完成copy.copy(iter(range(10**1000))),并且没有任何显着的内存使用情况。)

每个迭代器类型都不同,并且可能会或可能不会定义复制自身的方式。看起来你可以复制范围迭代器,但这并不意味着你可以假设你能够复制你遇到的任何迭代器。事实上,一般情况下,假设你不能这样做会更安全,因为迭代器协议相当普遍,许多迭代器不会公开复制它们所需的内部状态。

+0

@mgilson,BrenBarn,谢谢你的回答。他们似乎相容,这总是让人放心。只是为了让我看清楚这一点;你是否说它基本上归结为可拣性?那些需要缓冲的迭代器通常不被支持?如果你没有注意到我已经用迭代器更新了这个问题(以及我已经检查过的迭代器)。 –

+0

@PaulPanzer:我在我的回答中添加了一些注释。基本上,能够复制一个迭代器与复制其他任何东西没有什么不同:如果它定义了复制自己的方法,则可以复制它,否则不能。看起来你发现了一些可以被复制的迭代器,但是并没有真正说出是否可以复制一般的迭代器。此外,迭代器通常依赖于“私有”内部状态,因此遇到的随机迭代器可能比您遇到的其他随机对象更难以复制。 – BrenBarn