Изменение количества итераций в цикле for

У меня такой код:

loopcount = 3
for i in range(1, loopcount)
   somestring = '7'
   newcount = int(somestring)
   loopcount = newcount

поэтому я хочу изменить диапазон для внутри цикла.

Я написал этот код, ожидая, что диапазон цикла for изменится на (1,7) в течение первого цикла, но этого не произошло.

Вместо этого, независимо от того, какой номер я вставляю, он работает только 2 раза. (Я хочу 6 раз.. в этом случае)

Я проверил значение с помощью печати следующим образом:

    loopcount = 3
    for i in range(1, loopcount)
       print loopcount
       somestring = '7'
       newcount = int(somestring)
       loopcount = newcount
       print loopcount
#output:
3
7
7
7

Что не так? номер был изменен.

Где мое мышление не так?

Ответ 1

Диапазон создается на основе значения loopcount в момент его вызова - все, что происходит с петлей, впоследствии не имеет значения. То, что вы, вероятно, хотите, это оператор while:

loopcount = 3
i = 1
while i < loopcount:
    somestring = '7'
    loopcount = int(somestring)
    i += 1

Тест while проверяет, что условие i < loopcount истинно, и если оно истинно, если выполняется содержащиеся в нем утверждения. В этом случае на каждом прохождении через цикл я увеличивается на 1. Так как в первый раз цикл петли устанавливается на 7, цикл будет работать шесть раз, для я = 1,2,3,4,5 и 6.

Когда условие ложно, когда i = 7, цикл while перестает работать.

(Я не знаю, каков ваш фактический вариант использования, но вам может не понадобиться назначать newcount, поэтому я удалил это).

Ответ 2

Из range() docstring:

range ([start,] stop [, step]) → список целых чисел

Возвращает список, содержащий арифметическую прогрессию целых чисел. диапазон (i, j) возвращает [i, я + 1, я + 2,..., j-1]; start (!) по умолчанию 0. Когда задан шаг, он указывает прирост (или декремент). Например, диапазон (4) возвращает [0, 1, 2, 3]. Конечная точка опущена! Это точно допустимые индексы для списка из 4 элементов.

Итак, range(1, 10), например, возвращает список вроде: [1,2,3,4,5,6,7,8,9], поэтому ваш код в основном выполняет:

loopcount = 3
for i in [1, 2]:
    somestring = '7'
    newcount = int(somestring)
    loopcount = newcount

Когда ваш цикл for "инициализирован", список создается range().

Ответ 3

Ответ while-loop, заданный пользователем802500, скорее всего, будет лучшим решением вашей реальной проблемы; однако, я думаю, что вопрос , как задал, имеет интересный и поучительный ответ.

Результат вызова range() - это список последовательных значений. Цикл for-loop повторяется над этим списком до тех пор, пока он не будет исчерпан.

Вот ключевой момент: Вам разрешено мутировать список во время итерации.

>>> loopcount = 3
>>> r = range(1, loopcount)
>>> for i in r:
        somestring = '7'
        newcount = int(somestring)
        del r[newcount:]

Практическое использование этой функции - это повторение задач в списке задач и предоставление некоторым задачам генерации новых todos:

for task in tasklist:
    newtask = do(task)
    if newtask:
        tasklist.append(newtask)

Ответ 4

Чтобы конкретно задать вопрос "Как изменить границы диапазона", вы можете воспользоваться методом отправки для генератора:

def adjustable_range(start, stop=None, step=None):
    if stop is None:
        start, stop = 0, start

    if step is None: step = 1

    i = start
    while i < stop:
        change_bound = (yield i)
        if change_bound is None:
            i += step
        else:
            stop = change_bound

Использование:

myrange = adjustable_range(10)

for i in myrange:
    if some_condition:
        myrange.send(20) #generator is now bounded at 20

Ответ 5

Когда функция range() оценивается в for -loop, она генерирует последовательность значений (то есть список), которая будет используется для перебора.

range() использует для этого значение loopcount. Однако, как только эта последовательность будет сгенерирована, вы ничего не сделаете внутри цикла, измените этот список, т.е. Даже если вы измените loopcount позже, исходный список останется таким же = > количество итераций останется неизменным.

В вашем случае:

loopcount = 3
for i in range(1, loopcount):

становится

for i in [1, 2]:

Итак, ваш цикл повторяется дважды, так как у вас есть 2 print оператора в цикле, вы получаете 4 строки вывода. Обратите внимание, что вы печатаете значение loopcount, изначально 3, но затем устанавливаете (и reset) на 7.

Если вы хотите иметь возможность изменить число итераций динамически, используйте вместо этого while -loop. Конечно, вы всегда можете остановить/выйти из любого цикла раньше с помощью оператора break.

Кроме того,

   somestring = '7'
   newcount = int(somestring)

можно упростить до простого

   newcount = 7

Ответ 6

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

if i == some_calculated_threshold:
    break

чтобы отказаться от цикла.

Ответ 7

Вы не можете увеличить количество итераций после того, как диапазон был установлен, но вы можете вырваться раньше, тем самым уменьшив количество итераций:

for i in xrange(1, 7):
   if i == 2:
       break

Ответ 8

Вот более полная реализация функции adjustable_range, предоставленной Джоэлом Корнеттом.

def adjustable_range(start, stop=None, step=None):
    if not isinstance(start, int):
        raise TypeError('start')
    if stop is None:
        start, stop = 0, start
    elif not isinstance(stop, int):
        raise TypeError('stop')
    direction = stop - start
    positive, negative = direction > 0, direction < 0
    if step is None:
        step = +1 if positive else -1
    else:
        if not isinstance(step, int):
            raise TypeError('step')
        if positive and step < 0 or negative and step > 0:
            raise ValueError('step')
    if direction:
        valid = (lambda a, b: a < b) if positive else (lambda a, b: a > b)
        while valid(start, stop):
            message = yield start
            if message is not None:
                if not isinstance(message, int):
                    raise ValueError('message')
                stop = message
            start += step