复制可迭代对象的 Pythonic 方式
对于我正在进行的一个小项目,我需要循环浏览一个列表。对于此循环的每个元素,我必须通过同一列表启动另一个循环,前一个元素作为新循环的第一个元素。例如,我希望能够生成这样的东西:
1, 2, 3, 4, 1, 2, 3, 4, 1, ...
2, 3, 4, 1, 2, 3, 4, 1, 2, ...
3, 4, 1, 2, 3, 4, 1, 2, 3, ...
4, 1, 2, 3, 4, 1, 2, 3, 4, ...
1, 2, 3, 4, 1, 2, 3, 4, 1, ...
...
我认为在每个 .next() 之后复制 itertools.cycle 将保留当前状态,以便我可以使用“外部”中的元素开始新的循环“ 循环。或者甚至“重置循环指针”到较旧的位置。我尝试了以下操作:
>>> import itertools, copy
>>> a = itertools.cycle([1, 2, 3, 4])
>>> b = copy.copy(a)
但得到了这个错误:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python2.6/copy.py", line 95, in copy
return _reconstruct(x, rv, 0)
File "/usr/lib/python2.6/copy.py", line 323, in _reconstruct
y = callable(*args)
File "/usr/lib/python2.6/copy_reg.py", line 93, in __newobj__
return cls.__new__(cls, *args)
TypeError: cycle expected 1 arguments, got 0
我知道有很多不同的方法可以实现我想要的,但我正在寻找一些简短、清晰和Pythonic的代码。也许有人有另一个想法,甚至是一个片段?事实上,不可能复制迭代器对象唤醒了我的兴趣。当人们想要一份可迭代对象的副本时,是否有最佳实践?或者复制可迭代对象通常是愚蠢且无用的?
For a small project I'm working on I need to cycle through a list. For each element of this cycle I have to start another cycle through the same list, with the former element as first element of the new cycle. For example I'd like to be able to produce something like this:
1, 2, 3, 4, 1, 2, 3, 4, 1, ...
2, 3, 4, 1, 2, 3, 4, 1, 2, ...
3, 4, 1, 2, 3, 4, 1, 2, 3, ...
4, 1, 2, 3, 4, 1, 2, 3, 4, ...
1, 2, 3, 4, 1, 2, 3, 4, 1, ...
...
I thought that copying a itertools.cycle after each .next() would conserve the current state, so that I can begin the new cycle with the element from the "outer" cycle. Or even "reset the cycle pointer" to an older position. I tried the following:
>>> import itertools, copy
>>> a = itertools.cycle([1, 2, 3, 4])
>>> b = copy.copy(a)
but got this error:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python2.6/copy.py", line 95, in copy
return _reconstruct(x, rv, 0)
File "/usr/lib/python2.6/copy.py", line 323, in _reconstruct
y = callable(*args)
File "/usr/lib/python2.6/copy_reg.py", line 93, in __newobj__
return cls.__new__(cls, *args)
TypeError: cycle expected 1 arguments, got 0
I know there are many different ways to achieve what I want but I'm looking for some short, clear and pythonic code. Maybe someone has another idea or even a snippet? The fact that it's not possible to copy iterator objects woke my interest. Is there a best-practice in situations where one wants a copy of an iterable? Or is copying iterables silly and useless in general?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
itertools.tee 为您提供两个迭代器,每个迭代器产生与原始迭代器相同的项目,但它采用原始迭代器并记住它产生的所有内容,因此您不能再使用原始迭代器。但这在这里没有帮助,因为它会继续记住这些循环值,直到出现 MemoryError 为止。
迭代器只是定义为具有当前状态并产生一个项目。你无法判断他们将来是否会产生相同的物品,或者他们过去产生了哪些物品。真正的副本必须同时做到这两点,所以这是不可能的!
在你的情况下,创建一个新的循环是如此微不足道,我宁愿这样做也不愿尝试复制现有的循环。例如:
itertools.tee
gives you two iterators that each yield the same items as the original, but it takes the original and memorizes everything it yields, so you can't use the original anymore. It wouldn't help here though, because it would keep on memorizing these cycled values until you get a MemoryError.iterators are just defined to have a current state and yield a item. You can't tell if they will yield the same items in the future or which items they yielded in the past. A real copy would have to do both, so it's impossible!
In your case it's so trivial to make a new cycle that I'd rather do that than try to copy an existing. For example: