这是一个人为的例子:
from itertools import cycle
def foobar():
A = [1,2,3,4,5]
B = [6,7,8,9,10]
it = cycle(A)
tmp=0
for item in it:
print item, tmp
if tmp>10:
it=cycle(B) #is this possible?
if tmp>30:
return tmp
tmp+=item
输出:
1 0
2 1
3 3
4 6
5 10
1 15
2 16
3 18
4 21
5 25
1 30
2 31
我试图在for循环中迭代一个iterable直到满足条件,此时我重新定义 it 以便它使用相同的循环体迭代另一个列表
代码无法以我当前的形式运行:它继续使用循环(A),即使我重新定义了 it = cycle( B)。我想有一些范围问题,循环内的代码无法修改循环条件。有没有办法完成我在这里尝试做的事情,或者我需要制作重复或嵌套的for循环来迭代多个列表?
答案 0 :(得分:1)
没有办法直接做你想做的事。代码中的for
循环仅引用首次启动时传递的可迭代的初始值。它在该iterable上调用iter()
并使用它获取的迭代器来获取迭代的项。重新绑定在for
中使用的变量不会改变任何内容,因为在获得迭代器之后,循环的内部逻辑不会使用该变量。
我怀疑使用break
,另一个循环将是解决此问题的最佳方法。但是如果确实希望保持循环代码尽可能接近你当前的代码,那么你可以编写自己的迭代器,它允许从一个(内部存储的)迭代器交换到另一个迭代器:
class swapable_iterator(object):
def __init__(self, it):
self.it = it
def __iter__(self):
return self
def next(self):
return next(self.it)
__next__ = next # Python 3 compatibility
def swap(self, new_it):
self.it = new_it
你仍然需要稍微改变你的循环逻辑,因为它目前会一遍又一遍地交换cycle(B)
(tmp > 10
之后),只看到第一个值。
尝试类似:
def foobar():
A = [1,2,3,4,5]
B = [6,7,8,9,10]
it = swapable_iterator(cycle(A)) # wrap the cycle with our custom iterator object
tmp=0
for item in it:
print item, tmp
if item == 5 and tmp > 10: # this will happen exactly once with the A and B above
it.swap(cycle(B)) # this modifies "it" in place, rather than rebinding it
if tmp>30:
return tmp
tmp+=item
答案 1 :(得分:0)
我认为不可能改变for循环的条件。您总是可以使用while和some语句来更改要使用的迭代器的下一项,例如:
from itertools import cycle
def foobar():
A = [1, 2, 3, 4, 5]
B = [6, 7, 8, 9, 10]
tmp = 0
iter_A = cycle(A)
iter_B = cycle(B)
use_A = True
while True:
if use_A:
item = next(iter_A)
else:
item = next(iter_B)
print item, tmp
if tmp > 10:
use_A = False
if tmp > 30:
return tmp
tmp += item
输出:
1 0
2 1
3 3
4 6
5 10
1 15
6 16
7 22
8 29
9 37
我希望这会有所帮助。
<强>更新强>
根据Martijn Pieters的评论,以下内容也应该有效:
from itertools import cycle
def foobar():
A = [1, 2, 3, 4, 5]
B = [6, 7, 8, 9, 10]
tmp = 0
iter_A = cycle(A)
iter_B = cycle(B)
it = iter_A
while True:
item = next(it)
print item, tmp
if tmp > 10:
it = iter_B
if tmp > 30:
return tmp
tmp += item