【问题标题】:for loops in Python - how to modify i inside the loopPython 中的 for 循环 - 如何在循环内修改 i
【发布时间】:2023-03-14 14:36:01
【问题描述】:

此代码是在 Jupyter Notebooks 中用 Python 3.6 编写的。在其他语言中,我很确定我构建了如下所示的循环:

endRw=5
lenDF=100   # 1160

for i in range(0, lenDF):
    print("i: ", i)
    endIndx = i + endRw
    if endIndx > lenDF:
                endIndx = lenDF

    print("Range to use: ", i, ":", endIndx)
    # this line is a mockup for an index that is built and used
    # in the real code to do something to a pandas DF

    i = endIndx
    print("i at end of loop", i)

但在测试中,i 不会重置为 endIndx,因此循环不会构建预期的索引值。

我能够通过构建这样的 while 循环来解决这个问题并得到我想要的:

endRw=5
lenDF=97   # 1160
i = 0
while i < lenDF:
    print("i: ", i)
    endIndx = i + endRw
    if endIndx > lenDF:
                endIndx = lenDF

    print("Range to use: ", i, ":", endIndx)
    # this line is a mockup for an index that is built and used
    # in the real code to do something to a pandas DF

    i = endIndx
    print("i at end of loop: ", i)

问题:有没有办法从 python 中的for 循环内部修改i?有没有办法在 Python 中使用 for 循环来完成我对 while 循环所做的事情?

用while 解决了这个问题,但只是对此感到好奇。

【问题讨论】:

  • 你没有明确你的目标到底是什么。如果您只想结束整个循环,请使用break。
  • @KlausD。 - 我的测试循环的输出有点长,但是如果您在 Python 中运行 while 循环,目标是获得与 while 循环生成的输出相同的输出,但使用 for 循环进行。更具体地说,我最初遇到了麻烦,因为我在其他语言中修改了 for 循环中的 i 变量,就像我在所示的 for 循环中尝试的方式一样,但它在 Python 中不起作用,我在这里看到了一些很好的答案为什么我将不得不进行一些测试,以确定哪个最接近我认为的目标。
  • @TMWP 刚刚看到您对我的回答的编辑被拒绝。你为什么不把它作为一个单独的答案呢?我认为这是值得的。
  • @PaulPanzer 它采用了您向我展示的概念并将它们集成到原始代码中,以便它们工作。在这方面,它对我来说并不是一个新的答案,而是一个更完整的答案。此外,以我的拙见借用您的概念的答案不应与您的答案竞争。如果您现在无法取消或接受我上一次被拒绝的编辑,但喜欢这个想法,请告诉我,我会再次编辑,以便您接受。
  • @PaulPanzer 如果在阅读了我之前的评论后,您仍然认为它需要作为新答案发布,请告诉我,我可能会这样做。我只是喜欢添加到您的完整性的想法。

标签: python for-loop


【解决方案1】:

for 循环在可迭代对象上运行。在for i in range(0, lenDF) 中,i 在循环的每一轮中被分配范围内的下一个值,无论它在循环中如何使用。那么问题是,是否有一种干净的方法来编写一个可以满足您需求的可迭代对象。在这种情况下,您只需按固定步长前进并调整最终步长以考虑数据的结尾。

endRw=5
lenDF=97   # 1160

for i in range(0, lenDF, endRw):
    endIndx = min(i+endRw, lenDF)
    print("Range to use: ", i, ":", endIndx)

【讨论】:

    【解决方案2】:

    您可以在for 循环中修改循环变量,问题是Python 中的for 循环不像例如“旧式”for 循环。 Java,但更像是“新式”for-each 循环。

    在 Python 中,for i in range(0, 10): 的行为不像 for (int i = 0; i &lt; 10; i++) {,而是像 for (int i : new int[] {0, 1, ..., 10}}。

    也就是说,在循环的每次迭代中,循环头不会修改循环变量(例如递增它),而是为其分配一个新值,即给定的下一个值可迭代(在您的情况下为range)。因此,您在上一次迭代中所做的任何修改都会被覆盖。

    如果您想循环已知数量的迭代或对于可迭代中的每个项目,请使用 for 循环,但如果您想循环直到某个条件(不再)成立,就像您的情况一样,请使用while.

    【讨论】:

      【解决方案3】:

      这个答案不太可能有用,但由于您只是好奇: 我认为最接近您想要做的是使用生成器及其send 方法:

      >>> def jumpable_range(start, stop):
      ...     i = start
      ...     while i <= stop:
      ...         j = yield i
      ...         i = i + 1 if j is None else j
      ... 
      >>> R = jumpable_range(2, 10)
      >>> 
      >>> for i in R:
      ...     if i==5:
      ...         i = R.send(8)
      ...     print(i)
      ... 
      2
      3
      4
      8
      9
      10
      >>> 
      

      【讨论】:

      • 我喜欢这个解决方案。它是一种向迭代器提供反馈的更通用的方法。我认为在特定情况下不需要它,但值得注意。如果它同时返回 i 和结束索引会很有趣,这样调用者就不需要进行那个计算了。
      【解决方案4】:

      从字面上理解原始问题:

      • @Tobias_k 提供了a good explanation 何时使用while 与for 循环,并且这个问题的用例更适合while(至少对于Python)。简而言之:您不能直接修改for i in 中的i,因为此代码在Python 中是如何工作的。因此,while 应该用于需要在循环内(在 Python 中)更改计数器的用例。
      • @tdelaney 在使用 Python for 循环重构代码方面提供了一个很好的答案,因为 Python 的行为方式(accepted answer 这个问题)。
      • @PaulPanzer provides concepts 虽然过于复杂,但对学生探索新概念很有用;但答案通过在迭代器中使用while 循环并将其调用到for 循环中来解决for 循环问题。

      即便如此,使用yield 和迭代器探索的概念还是值得探索的。如果我们采用这些概念并尝试重写原始代码以利用它们,那么代码将如下所示:

      def jumpable_range(start, stop):
          i = start
          while i <= stop:
              j = yield i
              i = i + 1 if j is None else j
      
      endRw=5
      lenDF=97   # 1160
      
      Q = jumpable_range(0,lenDF)
      for i in Q:
          print("i: ", i)
          endIndx = i + endRw
          if endIndx > lenDF:
                      endIndx = lenDF
      
          if i == endIndx: break
      
          print("Range to use: ", i, ":", endIndx)
          # this line is a mockup for an index that is built and used
          # in the real code to do something to a pandas DF
      
          i = Q.send(endIndx-1)
          print("i at end of loop", i)
      

      【讨论】:

      • 不错的总结。一点点挑剔:jumpable_range 不是函数,而是生成器。
      • 谢谢。现在解决这个问题。
      【解决方案5】:

      您始终可以在for 循环中设置i 的值。问题是您的设置值语句在隐式 for 循环设置值语句之前并被后者覆盖。您不能更改规则以使后面的语句无用。即使可以,您也不应该这样做。只需更改为使用适当的条件变量即可。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-10-28
        • 1970-01-01
        • 1970-01-01
        • 2016-04-25
        • 1970-01-01
        相关资源
        最近更新 更多