【问题标题】:Redo for loop iteration in Python在 Python 中重做 for 循环迭代
【发布时间】:2016-08-03 01:53:06
【问题描述】:

Python 是否有某些语言中存在的“重做”语句形式的东西?

(“redo”语句是(就像“break”或“continue”一样)影响循环行为的语句 - 它在最内层循环的开头跳转并再次开始执行。)

【问题讨论】:

  • 有很多方法可以做到这一点。一方面,您可以使用while 循环并在某些评估时重置您的计数器/条件。
  • 从来没有听说过这样的事情。听起来很像 goto
  • @ChristopherSchneider:Perl 使用它(为了它的价值)。想想不执行循环推进步骤的continue。由于它与循环本身相关联,因此它在道德上与continuebreak 并没有真正的区别;如果您接受它们不仅仅是goto,那么redo 不会更糟(或更好)。

标签: python python-2.7 for-loop redo


【解决方案1】:

不,Python 不直接支持redo。一种选择是涉及嵌套循环的一些可怕的事情,例如:

for x in mylist:
    while True:
        ...
        if shouldredo:
            continue  # continue becomes equivalent to redo
        ...
        if shouldcontinue:
            break     # break now equivalent to continue on outer "real" loop
        ...
        break  # Terminate inner loop any time we don't redo

但这意味着在“redo-able”块中breaking 外部循环是不可能的,除非诉诸异常、标记变量或将整个事情打包成一个函数。

或者,您可以使用直接的while 循环来复制for 循环为您所做的事情,显式地创建和推进迭代器。它有自己的问题(continue 默认情况下实际上是redo,您必须显式推进迭代器以获得“真实”continue),但它们并不可怕(只要您评论@987654330 的使用@ 明确表示您打算使用redocontinue,以避免混淆维护者)。要允许 redo 和其他循环操作,您可以执行以下操作:

# Create guaranteed unique sentinel (can't use None since iterator might produce None)
sentinel = object()
iterobj = iter(mylist)  # Explicitly get iterator from iterable (for does this implicitly)
x = next(iterobj, sentinel)  # Get next object or sentinel
while x is not sentinel:     # Keep going until we exhaust iterator
    ...
    if shouldredo:
        continue
    ...
    if shouldcontinue:
        x = next(iterobj, sentinel)  # Explicitly advance loop for continue case
        continue
    ...
    if shouldbreak:
        break
    ...
    # Advance loop
    x = next(iterobj, sentinel)

上述操作也可以使用try/except StopIteration: 而不是两个参数nextsentinel 来完成,但是用它包裹整个循环可能会导致StopIteration 的其他来源被捕获,并且对于内部和外部next 调用在有限范围内正确执行此操作将非常难看(比基于sentinel 的方法差得多)。

【讨论】:

  • 这应该是公认的答案。重做不会是非常pythonic,并且在必要时模拟你的for循环并标记重做将很容易被其他人遵循。谢谢
【解决方案2】:

不,它没有。我建议使用 while 循环并将您的检查变量重置为初始值。

count = 0
reset = 0
while count < 9:
   print 'The count is:', count
   if not someResetCondition:
       count = count + 1

【讨论】:

  • 使用reset 不会复制redo 在其他语言中的作用。 redocontinue 没有循环增量/提前步骤,但它不会从头开始重新启动循环;您只需将 count 增量设为可选,没有 reset 变量。
  • 啊,我误读了您的初始陈述“它在开头跳跃”是指初始点,而不仅仅是循环的顶部。我会修改我的答案。
  • 我不是 OP,这是他们最初的声明,不是我的。我承认我可能误读了,但我所知道的与redo 相关的唯一语言是 Perl,它的行为方式是这样的。注意:如果您要替换 for count in range(10):,编辑后的代码很好,但它并不是特别适用于任意迭代;我在my answer 中的第二个代码示例是完全通用的版本。
【解决方案3】:

我在学习perl时遇到同样的问题,我找到了这个页面。

按照perl的书:

my @words = qw(fred barney pebbles dino wilma betty);
my $error = 0;

my @words = qw(fred barney pebbles dino wilma betty);
my $error = 0;

foreach (@words){
    print "Type the word '$_':";
    chomp(my $try = <STDIN>);
    if ($try ne $_){
        print "Sorry - That's not right.\n\n";
        $error++;
        redo;
    }
}

以及如何在 Python 上实现它? 按照代码:

tape_list=['a','b','c','d','e']

def check_tape(origin_tape):
    errors=0
    while True:
        tape=raw_input("input %s:"%origin_tape)
        if tape == origin_tape:
            return errors
        else:
            print "your tape %s,you should tape %s"%(tape,origin_tape)
            errors += 1
            pass

all_error=0
for char in tape_list:
    all_error += check_tape(char)
print "you input wrong time is:%s"%all_error

Python 没有“重做”语法,但我们可以在某个函数中创建一个“while”循环,直到我们迭代列表时得到我们想要的。

【讨论】:

    【解决方案4】:

    这是我使用迭代器的解决方案:

    class redo_iter(object):
        def __init__(self, iterable):
            self.__iterator = iter(iterable)
            self.__started = False
            self.__redo = False
            self.__last = None
            self.__redone = 0
        def __iter__(self):
            return self
        def redo(self):
            self.__redo = True
        @property
        def redone(self):
            return self.__redone
        def __next__(self):
            if not (self.__started and self.__redo):
                self.__started = True
                self.__redone = 0
                self.__last = next(self.__iterator)
            else:
                self.__redone += 1
            self.__redo = False
            return self.__last
    
    
    # Display numbers 0-9.
    # Display 0,3,6,9 doubled.
    # After a series of equal numbers print --
    iterator = redo_iter(range(10))
    for i in iterator:
        print(i)
        if not iterator.redone and i % 3 == 0:
            iterator.redo()
            continue
        print('---')
    
    • 需要明确的continue
    • redone 是一个额外的功能
    • 对于 Python2 使用 def next(self) 而不是 def __next__(self)
    • 需要在循环之前定义iterator

    【讨论】:

      【解决方案5】:

      不是很复杂但易于阅读,使用while 和循环结束时的增量。所以介于两者之间的任何continue 都会产生重做的效果。每 3 的倍数重做一次采样:

      redo = True # To ends redo condition in this sample only
      i = 0
      while i<10:
         print(i, end='')
         if redo and i % 3 == 0:
            redo = False # To not loop indifinively in this sample
            continue # Redo
         redo = True
         i += 1
      

      结果:00123345667899

      【讨论】:

        【解决方案6】:

        python 中没有重做。 一个非常容易理解的解决方案如下:

        for x in mylist:
            redo = True
            while redo:
                redo = False
        
                If should_redo:
                    redo = True
        

        不加cmets就够清楚了

        Continue 将像在 for 循环中一样工作

        break 不可用,这个solution 使break 可用但代码不太清楚。

        【讨论】:

          【解决方案7】:

          这是python 3.8+的解决方案,因为现在我们有the := operator

          for key in mandatory_attributes:  # example with a dictionary
              while not (value := input(f"{key} (mandatory): ")):
                  print("You must enter a value")
          
              mandatory_attributes[key] = value
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2012-06-27
            • 2023-03-05
            • 1970-01-01
            • 2018-11-21
            • 1970-01-01
            • 1970-01-01
            • 2016-01-18
            • 2015-03-14
            相关资源
            最近更新 更多