Changing the number of iterations in a for loop

前端 未结 8 1277
死守一世寂寞
死守一世寂寞 2020-12-10 11:27

I have code like this:

loopcount = 3
for i in range(1, loopcount)
   somestring = \'7\'
   newcount = int(somestring)
   loopcount = newcount
相关标签:
8条回答
  • 2020-12-10 11:56

    When the range() function is evaluated in the for-loop it generates a sequence of values (ie a list) that will be used to iterate over.

    range() uses the value of loopcount for this. However, once that sequence has been generated, nothing you do inside the loop will change that list, i.e., even if you change loopcount later, the original list will stay the same => the number of iterations will stay the same.

    In your case:

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

    becomes

    for i in [1, 2]:
    

    So your loop iterates twice, since you have 2 print statements in the loop your get 4 lines of output. Note that you are printing the value of loopcount which is initially 3, but then gets set (and reset) to 7.

    If you want to be able to change the iteration number dynamically consider using a while-loop instead. Of course you can always stop/exit any loop early with the use of the break statement.

    Also,

       somestring = '7'
       newcount = int(somestring)
    

    can be simplified to just

       newcount = 7
    
    0 讨论(0)
  • 2020-12-10 11:56

    It looks like your premise is that you have a default number of times the loop should execute but an occasional condition where it's different. It might be better to use a while loop instead, but regardless you can just do:

    if i == some_calculated_threshold:
        break
    

    to drop out of the loop instead.

    0 讨论(0)
  • 2020-12-10 11:56

    Here is a more complete implementation of the adjustable_range function provided by Joel Cornett.

    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
    
    0 讨论(0)
  • 2020-12-10 12:01

    From the range() docstring:

    range([start,] stop[, step]) -> list of integers

    Return a list containing an arithmetic progression of integers. range(i, j) returns [i, i+1, i+2, ..., j-1]; start (!) defaults to 0. When step is given, it specifies the increment (or decrement). For example, range(4) returns [0, 1, 2, 3]. The end point is omitted! These are exactly the valid indices for a list of 4 elements.

    So, range(1, 10), for example, returns a list like: [1,2,3,4,5,6,7,8,9], so, your code is basically doing:

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

    When your for loop is "initialized", the list is created by range().

    0 讨论(0)
  • 2020-12-10 12:03

    The while-loop answer given by user802500 is likely to be the best solution to your actual problem; however, I think the question as asked has an interesting and instructive answer.

    The result of the range() call is a list of consecutive values. The for-loop iterates over that list until it is exhausted.

    Here is the key point: You are allowed to mutate the list during iteration.

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

    A practical use of this feature is iterating over tasks in a todo list and allowing some tasks to generate new todos:

    for task in tasklist:
        newtask = do(task)
        if newtask:
            tasklist.append(newtask)
    
    0 讨论(0)
  • 2020-12-10 12:13

    To specifically address the question "How do I change the range bounds", you can take advantage of the send method for a generator:

    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
    

    Usage:

    myrange = adjustable_range(10)
    
    for i in myrange:
        if some_condition:
            myrange.send(20) #generator is now bounded at 20
    
    0 讨论(0)
提交回复
热议问题