Scope of python variable in for loop

前端 未结 10 1853
一整个雨季
一整个雨季 2020-11-22 15:16

Heres the python code im having problems with:

for i in range (0,10):
    if i==5:
        i+=3
    print i

I expected the output to be:

相关标签:
10条回答
  • 2020-11-22 16:02
    it = iter(xrange (0,10))
    for i in it:
        if i==4: all(it.next() for a in xrange(3))
        print i
    

    or

    it = iter(xrange (0,10))
    itn = it.next
    for i in it:
        if i==4: all(itn() for a in xrange(3))
        print i
    
    0 讨论(0)
  • 2020-11-22 16:09

    Analogy with C code

    You are imagining that your for-loop in python is like this C code:

    for (int i = 0; i < 10; i++)
        if (i == 5)
            i += 3;
    

    It's more like this C code:

    int r[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
    for (int j = 0; j < sizeof(r)/sizeof(r[0]); j++) {
        int i = r[j];
        if (i == 5)
            i += 3;
    }
    

    So modifying i in the loop does not have the effect you expect.

    Disassembly example

    You can look at the disassembly of the python code to see this:

    >>> from dis import dis
    >>> def foo():
    ...     for i in range (0,10):
    ...         if i==5:
    ...             i+=3
    ...         print i
    ... 
    >>> dis(foo)
      2           0 SETUP_LOOP              53 (to 56)
                  3 LOAD_GLOBAL              0 (range)
                  6 LOAD_CONST               1 (0)
                  9 LOAD_CONST               2 (10)
                 12 CALL_FUNCTION            2
                 15 GET_ITER            
            >>   16 FOR_ITER                36 (to 55)
                 19 STORE_FAST               0 (i)
    
      3          22 LOAD_FAST                0 (i)
                 25 LOAD_CONST               3 (5)
                 28 COMPARE_OP               2 (==)
                 31 POP_JUMP_IF_FALSE       47
    
      4          34 LOAD_FAST                0 (i)
                 37 LOAD_CONST               4 (3)
                 40 INPLACE_ADD         
                 41 STORE_FAST               0 (i)
                 44 JUMP_FORWARD             0 (to 47)
    
      5     >>   47 LOAD_FAST                0 (i)
                 50 PRINT_ITEM          
                 51 PRINT_NEWLINE       
                 52 JUMP_ABSOLUTE           16
            >>   55 POP_BLOCK           
            >>   56 LOAD_CONST               0 (None)
                 59 RETURN_VALUE        
    >>> 
    

    This part creates a range between 0 and 10 and realizes it:

              3 LOAD_GLOBAL              0 (range)
              6 LOAD_CONST               1 (0)
              9 LOAD_CONST               2 (10)
             12 CALL_FUNCTION            2
    

    At this point, the top of the stack contains the range.

    This gets an iterator over the object on the top of the stack, i.e. the range:

             15 GET_ITER  
    

    At this point, the top of the stack contains an iterator over the realized range.

    FOR_ITER begins iterating over the loop using the iterator at the top of th estack:

        >>   16 FOR_ITER                36 (to 55)
    

    At this point, the top of the stack contains the next value of the iterator.

    And here you can see that the top of the stack is popped and assigned to i:

             19 STORE_FAST               0 (i)
    

    So i will be overwritten regardless of what you do in the loop.

    Here is an overview of stack machines if you haven't seen this before.

    0 讨论(0)
  • 2020-11-22 16:10

    If for some reason you did really want to change add 3 to i when it's equal to 5, and skip the next elements (this is kind of advancing the pointer in C 3 elements), then you can use an iterator and consume a few bits from that:

    from collections import deque
    from itertools import islice
    
    x = iter(range(10)) # create iterator over list, so we can skip unnecessary bits
    for i in x:
        if i == 5:             
            deque(islice(x, 3), 0) # "swallow up" next 3 items
            i += 3 # modify current i to be 8
        print i
    
    0
    1
    2
    3
    4
    8
    9
    
    0 讨论(0)
  • 2020-11-22 16:15

    In python 2.7 range function create a list while in python 3.x versions it creates a 'range' class object which is only iterable not a list, similar to xrange in python 2.7.

    Not when you are iterating over range(1, 10), eventually you are reading from the list type object and i takes new value each time it reaches for loop.

    this is something like:

    for i in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]:
        if i==5:
            i+=3
        print(i)
    

    Changing the value wont change the iteration order from the list.

    0 讨论(0)
提交回复
热议问题