【问题标题】:Can I redefine the iterator variable in the body of a for-loop?我可以在 for 循环的主体中重新定义迭代器变量吗?
【发布时间】:2016-04-09 22:13:49
【问题描述】:

这是一个人为的例子:

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 循环中迭代一个可迭代对象,直到满足一个条件,此时我重新定义 it 以便它使用相同的循环体迭代另一个列表。

代码在当前形式下无法按照我希望的方式运行:它继续使用 cycle(A),即使在我重新定义 it=cycle(B) 之后也是如此。我想存在某种范围问题,循环内的代码无法修改循环条件。有什么方法可以完成我在这里尝试做的事情,还是我需要制作重复或嵌套的 for 循环来迭代多个列表?

【问题讨论】:

    标签: python-2.7 for-loop scope iterator


    【解决方案1】:

    没有办法直接做你想做的事。代码中的 for 循环仅引用您在首次启动时传递的可迭代对象的初始值。它在该可迭代对象上调用 iter() 并使用它获得的迭代器来获取要迭代的项目。重新绑定您在 for 中使用的变量不会改变任何内容,因为在获得迭代器后,循环的内部逻辑不会使用该变量。

    我怀疑使用break 和另一个循环将是解决此问题的最佳方法。但是如果你真的想让循环代码尽可能地接近你当前的代码,你可以编写你自己的迭代器,它可以根据需要从一个(内部存储的)迭代器交换到另一个: p>

    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
    

    【讨论】:

    • 这很有趣。可交换迭代器真的可以工作吗?如果 for 循环使用 iter() 的结果,那么如果您调用 it.swap 似乎会遇到与以前相同的问题,即它不会导致 for 循环重新评估迭代器并更改循环条件。感谢您的回答
    • 它是一个迭代器,所以它的__iter__方法返回self。您无法在原始代码中交换 it 的原因(作为 cycle 也是一个迭代器,其 __iter__ 方法返回 self)是您重新绑定名称 it,而不是修改迭代器到位。调用 it.swap(当 itswapable_iterator 时)将对其进行修改,因此循环将根据需要获取更改。
    【解决方案2】:

    我认为不可能在 for 循环中更改条件。您总是可以使用一段时间和一些语句来更改要使用的迭代器的下一项,例如:

    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
    

    【讨论】:

    • 不使用flag,直接使用it = iter_A,之后切换到it = iter_B
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-10
    • 2021-12-27
    • 2022-01-23
    • 2020-02-05
    • 1970-01-01
    • 2013-06-18
    相关资源
    最近更新 更多