【问题标题】:Make index go back in for loop让索引回到for循环
【发布时间】:2016-07-17 06:59:47
【问题描述】:

我试图在 Python 中创建一个brainf**k 解释器,并想出了如何执行循环的想法,因为我遇到了问题,但现在我需要让索引重新进入这样的 for 循环:

    for i in range(20):
        if i == 15:
            # Set i to 5
        print(i)

但我不需要将 15 替换为 5,而是返回索引: 实际结果:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    5
    16
    17
    18
    19

预期结果:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    5
    6
    7
    8
    9

我怎样才能做到这一点,所以我可以返回一个或循环?

【问题讨论】:

标签: python


【解决方案1】:

这是不可能的语言结构

python中的for循环构造为for loop_param in iterator: block_of_statements

这意味着迭代器存在并且定义在循环之外,并且参数要求迭代器给它下一个值。所以无论你给参数什么值,它都会在下一次迭代中继续原来的序列。

但是...您可以想象(并构建)接受重置条件的特殊迭代器。

class resetable_range:
    def __init__(self, val):
        self.max = val
        self.val = 0
    def __iter__(self):
        return self
    def __next__(self):
        val = self.val
        if self.val == self.max:
            raise StopIteration
        self.val += 1
        return val
    def reset(self, val):
        self.val = val

使用该对象,您可以:

l = resetable_range(5)
for i in l:
    print(i)
    if (i==3):
        l.reset(1)

你会得到:

0
1
2
3
1
2
3
1
2
3
...

【讨论】:

    【解决方案2】:

    简单的for…loop 是不可能的。

    可以用while循环和计数器来执行:

    i = 0
    while i < 20:
        i += 1
    
        if i == 15:
            i = 5
        print(i)
    

    另一种解决方案是使用协程:

    def co_counter():
        i = 0
        new_i = None
        while i < 20:
            if new_i is not None:
                i = new_i - 1
            new_i = yield i
            i += 1
    
    counter = co_counter()
    for i in counter:
        if i == 15:
            counter.send(5)
        print(i)
    

    【讨论】:

    • @haifzhan OP 如果原始代码正常工作,就会出现无限循环
    • 第一个例子帮我解决了这个问题,我只是用while循环替换了for循环。我知道我有一个无限循环,但在brainf**k 代码中,它并不总是无限的。我不喜欢对各种序列进行太多迭代,这正是我所需要的。
    【解决方案3】:

    不幸的是,for 循环中的索引器 Python 将在每次迭代到新项目时被分配。因此,您的一次性重新分配:

    if i == 15:
        i = 5
    

    在后续迭代中不会有太大帮助

    来自 Python for 语句文档:

    表达式列表被计算一次;它应该产生一个可迭代的 目的。为 expression_list 的结果创建一个迭代器。 然后,该套件为由提供的每个项目执行一次 迭代器,按索引升序排列。 每个项目依次是 使用分配的标准规则分配给目标列表, 然后执行套件。当物品用尽时(即 当序列为空时立即执行),else 子句中的套件, 如果存在,则执行,并且循环终止。

    换句话说,对于您的itemi,无论循环中发生什么,都将使用iterable object 中提供的下一个值重新分配,在您的情况下由range(20) 生成

    #at loop 15
    [0 1 2 ... 15 16 19] #i is progressively increasing independent from what happen in the loop block
               ^ #here is i
    
    change i to 5? you can, but only lasting for one loop!
    #you print i, it shows 5, and then...
    
    #at loop 16
    [0 1 2 ... 15 16 19]
                  ^ #still got reassigned at the beginning of the next loop
    

    一种方法是创建另一个索引器 - 独立于 for 循环,当您的 for 循环索引器 i 到达 15 时,该循环会重置:

    j = 0
    for i in range(20):
        if i == 15:
            j = 5;
        print(j)
        j = j + 1
    

    另一种不那么推荐的方法是每次在i &gt;= 15 之后重新分配i(您选择每次都与基本索引器重新分配作斗争)

    for i in range(20):
        if i >= 15:
            i = i - 10;
        print(i)
    

    【讨论】:

    • 两种方式都在打印0
    • @haifzhan 嗯是的,但是使用OP原码,也会先打印0,只是结果中不显示而已。请尝试一下...
    【解决方案4】:

    更系统地,您可以迭代一系列范围和序列:

    for r in [range(1,15),range(5,10)]:
        for i in r:
            print(i)
    

    range的第一个参数是第一个值,第二个参数是最后一个值的后继。

    你如何从 Brainf**k 解释器中得到这些奇怪的循环?

    【讨论】:

      【解决方案5】:

      for 循环的每次迭代都会从 range 创建的列表中提取i。 设置i=5 只会更改i 的那一次迭代。相反,您可以尝试附加两个范围:

      for i in range(15) + range(5,10):
          print(i)
      

      【讨论】:

      • 你试过你的代码了吗,它适用于python3.x吗?
      • 不,没试过。这就是为什么我要求 OP 尝试一下。但很高兴它给了你灵感@LorenzoGatti
      猜你喜欢
      • 1970-01-01
      • 2012-09-27
      • 1970-01-01
      • 1970-01-01
      • 2021-07-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多