для циклов в 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
оператор значения установки цикла и покрытый последним. Вы не можете изменить правило, чтобы сделать последнее утверждение бесполезным. Ты не должен этого делать, даже ты можешь. Просто измените, чтобы использовать правильную условную переменную.