1

I'm given the following program, and I've been asked to write down what it prints:

num = 10
for num in range(5):
    print(num)
print(num)

My answer is:

10

My reasoning is that num has been defined to be 10, so it can't be in the range (0,5), so we can skip this loop. Then, we simply write down what num is: 10.

The answer is very different:

0
1
2
3
4
4

How on earth is this the case, and how could the last line possibly print 4, when num has been defined to be 10 at the start?

Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
Steve Smith
  • 101
  • 1
  • 7
  • 1
    `num` in the `for` loop is being assigned whichever number in `range(5)` you are at in the iteration. `num` will be 0,1,2,3,4. – Nick Nov 02 '16 at 20:17
  • 2
    `for num in range(5)` overwrites the prior value. This isn't Haskell where a name can only be bound to one value. – Charles Duffy Nov 02 '16 at 20:18
  • 2
    You wouldn't skip the loop unless you had some logic like `if num in range(5):`, but you don't. You have `for num in range(5):`. I think you need to read up on your documentation again :) – David Zemens Nov 02 '16 at 20:18
  • 1
    @Eugene - Care to explain why you think that? – Nick Nov 02 '16 at 20:18
  • 1
    @Eugene, ...but I'm not sure that it is. The OP says they don't expect the `for` loop to be run *at all*, not that they don't expect its value to escape the scope after it completes. – Charles Duffy Nov 02 '16 at 20:19
  • 1
    LOL OK I see, OP doesn't quite understand loop variables... or maybe I still don't get it... – Eugene Nov 02 '16 at 20:21
  • I don't understand the linked answer at all, or all of the other stuff mentioned. If someone could explain where I'm going wrong in the context of really basic Python, that'd be great. – Steve Smith Nov 02 '16 at 20:23
  • @SteveSmith - That linked answer has nothing to do with your question. I think Eugene misunderstood. – Nick Nov 02 '16 at 20:23
  • @SteveSmith upvoted answer below is correct. – Eugene Nov 02 '16 at 20:23
  • @SteveSmith, ...so, the short answer is that `for num in range(5)` doesn't care what `num` was before the loop started. Doesn't look at it, doesn't evaluate it, isn't constrained by it, would behave in exactly the same way if the variable didn't exist before the loop was started at all, etc. So, do you know what your code would do if the `i = 10` line didn't exist? That's exactly the same as what it does here. – Charles Duffy Nov 02 '16 at 20:24
  • @SteveSmith, ...if that answer isn't good enough, we need to know more about your thought process to understand *why* it isn't good enough. – Charles Duffy Nov 02 '16 at 20:26
  • @SteveSmith would it be helpful if I totally broke it down for you in an answer? – Eugene Nov 02 '16 at 20:27
  • @CharlesDuffy Ok, but then why is a `4` printed, at the bottom, rather than a 10? `print(num)` exists outside the `for` loop, so why doesn't it go back to the original value of `num`. Surely, `num` has not been overwritten within the `for` loop. – Steve Smith Nov 02 '16 at 20:29
  • @SteveSmith - That is because `num` was last assigned 4 (inside the loop) and you are printing it twice. Once in the loop and once after the loop has exited. – Nick Nov 02 '16 at 20:30
  • @SteveSmith, why do you think "surely"? The loop doesn't have its own variable scope, so yes, indeed, it *does* overwrite the value. – Charles Duffy Nov 02 '16 at 20:47

4 Answers4

5

When you do:

for num in range(5):
    print(num)

The value you assigned to num via num = 10 is over ridden by the for loop. Within the loop, your num is varying from 0 to 4. And when the for loop ends, it holds the value as 4. Outside the loop when you do print num it prints 4 because it is holding that last assigned value within for.

Moinuddin Quadri
  • 46,825
  • 13
  • 96
  • 126
  • 1
    And also the fact that list comprehensions also "leak" their loop variable into the surrounding scope. You *should* technically see `10` printed at the end. Ref: https://www.python.org/dev/peps/pep-0289/ – Eugene Nov 02 '16 at 20:22
  • 4
    @Eugene This isn't "leak": it's been a part of Python for a long time and loops do not create a new scope. See http://stackoverflow.com/questions/3611760/scoping-in-python-for-loops – brianpck Nov 02 '16 at 20:24
  • 2
    @Eugene: It is actually not a leakage. It is the functionality as in python, loops do not have their own scope which applies to *list comprehension* as well. However, thanks for mentioning it as it might be useful to OP. – Moinuddin Quadri Nov 02 '16 at 20:28
  • @Eugene Python doesn't really have scopes. All names are bound to their surrounding function, like PHP. – melpomene Nov 02 '16 at 20:36
  • Got it. Leaking is essentially "non-garbage-collection", which is *not* occurring in this case, and I'm smoking crack thinking that Python has scope. Sorry everyone, it's been 30 hours coding in 5 languages... ah the joys of being a CTO... Apologies again to all, I've made a right Charlie Foxtrot out of this one... – Eugene Nov 02 '16 at 20:44
4

You are mixing up in (the boolean operator) with in (part of for syntax).

The following program is probably what you are thinking of:

>>> n = 10
>>> if n in range(5):
...     print(n)
...
>>> print(n)
10

In your test program, n loops through the values in range(5), printing those values. It then will print the last assigned value again, hence the repeated 4.

brianpck
  • 8,084
  • 1
  • 22
  • 33
1

the for loop will change the value of num from 0 to 4, what you are thinking is something like if num in range(5) that will ask if num is between (0, 5)

aleivag
  • 2,306
  • 1
  • 13
  • 13
0

As soon as the for in range loop starts, it overwrites the value of num. So, num starts with the value 10, it enters the for loop, it's value is then set to 0, it prints 0, num is set to 1, prints 1 and so on.

After the for loop, num is printed again, with its new value (the last value of the loop) 4.

Kyle Swanson
  • 455
  • 4
  • 11