для циклов в Python-как изменить i внутри цикла

этот код был написан на Python 3.6 В ноутбуках Jupyter. На других языках я уверен, что построил петли, которые выглядели так:

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)

вопрос: есть ли способ, чтобы изменить i изнутри the for цикл в python? Есть ли способ сделать то, что я сделал с while петли с помощью for цикл в Python?

решена проблема с while но просто любопытно об этом.

5 ответов


for циклы работают на iterables. В 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)

вы can измените переменную цикла в for цикл, проблема в том, что for петли в Python не похожи на" старый стиль"for петли, например, Java, но больше похоже на" новый стиль"for-each петли.

В Python, for i in range(0, 10): не ведет себя как for (int i = 0; i < 10; i++) {, а как for (int i : new int[] {0, 1, ..., 10}}.

то есть на каждой итерации цикла головка цикла не будет изменять переменную цикла (например, увеличивать ее), но присвоить ему новое значение, т. е. следующее значение из заданного iterable (a range в вашем случае). Таким образом, любые изменения, которые вы сделали в предыдущей итерации перезаписываются.

если вы хотите зациклить известное количество итераций или для каждого элемента в iterable, используйте for цикл, но если вы хотите цикл до определенного условия (больше не), как в вашем случае, используйте while.


этот ответ вряд ли будет полезен, но так как вы были просто любопытно: Ближе всего, я думаю, к тому, что вы хотите сделать, будет использовать генератор и его 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
>>> 

принимая первоначальный вопрос буквально:

  • @Tobias_k обеспечивает хорошее объяснение когда использовать while и for петли, и случай использования этого вопроса подходит while лучше (по крайней мере для Python). Короче говоря: вы не можете напрямую изменить i на for i in из-за того, как этот код работает под обложками в Python. Так что while следует использовать для случая использования, когда вам нужно изменить счетчик внутри цикла (в Питон.)
  • @tdelaney дает хороший ответ с точки зрения рефакторинга кода с помощью Python for цикл, учитывая поведение Python (принято отвечать на этот вопрос).
  • @PaulPanzer обеспечивает понятий это, хотя и слишком сложно, полезно для студентов, чтобы исследовать новые концепции; но ответ решает for проблема цикла с помощью while цикл внутри итератора и вызов этого в 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)

вы всегда можете задать значение i на for петли. Проблема в том, что ваш оператор установки значения находится перед неявным for оператор значения установки цикла и покрытый последним. Вы не можете изменить правило, чтобы сделать последнее утверждение бесполезным. Ты не должен этого делать, даже ты можешь. Просто измените, чтобы использовать правильную условную переменную.