如何使itertools.tee()产生迭代元素的副本?

时间:2017-01-15 12:46:01

标签: python generator itertools

我正在使用itertools.tee制作生成器的副本,这些生成器会产生字典并将迭代的字典传递给我无法控制的函数,并且可能会修改字典。因此,我想将字典的副本传递给函数,但是所有的tees都只产生对同一个实例的引用。

以下简单示例说明了这一点:

import itertools

original_list = [{'a':0,'b':1}, {'a':1,'b':2}]
tee1, tee2 = itertools.tee(original_list, 2)

for d1, d2 in zip(tee1, tee2):
    d1['a'] += 1
    print(d1)
    d2['a'] -= 1
    print(d2)

输出结果为:

{'b': 1, 'a': 1}
{'b': 1, 'a': 0}
{'b': 2, 'a': 2}
{'b': 2, 'a': 1}

虽然我想:

{'b': 1, 'a': 1}
{'b': 1, 'a': -1}
{'b': 2, 'a': 2}
{'b': 2, 'a': 0}

当然,在这个例子中有很多方法可以轻松地解决这个问题,但由于我的具体用例,我需要一个版本itertools.tee来存储所有迭代对象的副本。 tees而不是对原文的引用。

在Python中是否有直接的方法来执行此操作,或者我是否必须以非原生的方式重新实现itertools.tee,因此效率低下?

1 个答案:

答案 0 :(得分:1)

无需返工tee。只需将tee生成的每个生成器包装在map(dict, ...)生成器中:

try:
    # use iterative map from Python 3 if this is Python 2
    from future_builtins import map
except ImportError:
    pass

tee1, tee2 = itertools.tee(original_list, 2)
tee1, tee2 = map(dict, tee1), map(dict, tee2)

在迭代时,这会自动生成每个字典的浅表副本。

演示(使用Python 3.6):

>>> import itertools
>>> original_list = [{'a':0,'b':1}, {'a':1,'b':2}]
>>> tee1, tee2 = itertools.tee(original_list, 2)
>>> tee1, tee2 = map(dict, tee1), map(dict, tee2)
>>> for d1, d2 in zip(tee1, tee2):
...     d1['a'] += 1
...     print(d1)
...     d2['a'] -= 1
...     print(d2)
...
{'a': 1, 'b': 1}
{'a': -1, 'b': 1}
{'a': 2, 'b': 2}
{'a': 0, 'b': 2}