0

I'm trying to understand how Python 3 handles the index variable value at the completion of a for loop. I'm a python newbie, with prior programming experience in C, so at this point, I "think" in C, and try to construct the equivalent code in Python.

Here's a toy example . . .

def tst(n): return n==6

for i in range(8,0,-1):
    if tst(i): break
print(i)

for i in range(4,0,-1):
    if tst(i): break
print(i)

After the first loop completes, the value of the variable i is 6, as expected.

But after the second loop completes, I expected (from my C experience) that the value of i would be 0 (i.e., the final value of i would fall one past the end of the range, unless there was a break), but the actual value is 1.

I want it to be 0.

As an alternative, I could code the second loop this way:

i=4
while i>0:
   if tst(i): break
   i-=1
print(i)

which works the way I want.

Is that the way to do it?

Update:

Thanks to all for explaining how Python interprets range expressions.

Using juanpa.arrivillaga's suggestion, I've settled for the following . . .

for i in range(4,0,-1):
    if tst(i): break
else:
    i=0
print(i)
2
  • 1
    stop argument of for loop in python is not included Commented Sep 27, 2017 at 7:43
  • Caution: Before making the choice shown in the question update, please note that Guido van Rossum (creator of Python) said this about the using else on for / while loops: "I would not have the feature at all if I had to do it over." Commented Apr 18, 2022 at 17:38

4 Answers 4

6

You misunderstood how range() works; the stop value is not included:

>>> list(range(4, 0, -1))
[4, 3, 2, 1]

If you want the range to go down to 0, use -1 as the end value:

>>> list(range(4, -1, -1))
[4, 3, 2, 1, 0]

From the range() object documentation:

For a positive step, the contents of a range r are determined by the formula r[i] = start + step*i where i >= 0 and r[i] < stop.

For a negative step, the contents of the range are still determined by the formula r[i] = start + step*i, but the constraints are i >= 0 and r[i] > stop.

r[i] > stop means it'll never be equal to stop.

Your while loop decrements i after you tested it, so i > 0 is still true for i = 1, but then you substracted 1, making it i = 0, at which point the while test is false and the loop ends.

Note that you can't really compare Python's for construct with C for. The Python concept is a For each loop, while the C construct is really a setup, test, alter construct, which executes setup once, then repeats until the test fails, running the alter instructions after every repetition. This is what your while loop did too; the setup is i = 4, the test is i > 0 and the alter instruction is your i -= 1 at the end, at the end of the loop body.

If you wanted think about Python for loops in C terms, the closest I can think of is a for loop over a pointer:

int range[] = { 4, 3, 2, 1 }
for (int* p1=range; p1 < (range + (sizeof(range)/sizeof(range[0]))); p1++)
{
   // ...
} 

You'd have to add a , 0 in the range[] definition if you wanted it to continue on to 0. Python for loops handle any iterable however, including infinite generators; see the iterator protocol.

Sign up to request clarification or add additional context in comments.

9 Comments

But I don't want to actually pass 0 to tst. I Just want to know that the break didn't happen. So range(4,-1,-1) is not quite what I want.
Exactly. So I want the final i value to be the value of i for which tst returns True, or else, if the loop completes without a break, I want the value of i to be 0. My alternative example does just that.
@pyrat: then use range(4, -1, -1), because i is only ever going to be assigned values from the range() iterable. Python for loops are for each loops, not C for loops.
The problem with range(4,-1,-1) is that the actual tst (not the toy example) doesn't accept 0 as an input, only positive integers.
But I understand how it works now. Thanks for the explanation.
|
4

Thatś because the stop value it's not included. This it's the sintax of range:

range([start], stop[, step])

    start: Starting number of the sequence.
    stop: Generate numbers up to, but not including this number.
    step: Difference between each number in the sequence.

1 Comment

Thanks, I follow now. Nice explanation.
1

Here's the way to think about it. In Python, the for loop always iterates over a collection of objects. When the loop finishes, the index variable will always hold the last object from the collection. The thing that's tripping you up is that the Python range() function is non-inclusive at the end. See the documentation at https://docs.python.org/3/library/stdtypes.html#typesseq-range.

So in your case, the second loop is iterating correctly over range(4,0,-1), which is equivalent to [4, 3, 2, 1], not [4, 3, 2, 1, 0]. So i ends up with the last value in that collection, which is 1. If you want to include 0 in the range, you have to use range(4, -1, -1).

I find this behavior of range() confusing, but it's a very standard Python element. It works well if you want a loop to repeat n times -- just use range(n) to get [0, 1, ..., n-1]. String and collection indexing work similarly: mystring[:4] gives you everything before element 4 of mystring. That behavior can be nice if you are splitting strings: mystring[:4] gives you the first 4 characters, and then mystring[4:] gives you everything after that. This saves you from having to add 1 to your indexes in various places or remember to use i<3 (not i<=3) as you would in C.

On the other hand, if you want a list of numbers from 1 to 5 (inclusive), you have to remember to use something like range(1, 5+1). (I sometimes to use +1 as a reminder that this is forcing the range a little further, and so that the range call shows the actual stopping point somewhere.)

1 Comment

"Always iterates over a collection of objects." Nice. That resolves the confusion. Thanks.
0

the problem you have is with range(4,0,-1) this returns [4, 3, 2, 1] change it to range(4,-1,-1)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.