1

In C there is an option to decide whether we want to override a loop variable.

For example, i is overridden in this snippet:

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

But i is not overridden in this snippet:

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

Haven't found a similar option in Python.

For example, i is overridden in this snippet:

i = 3
for i in range(5):
    pass

How to prevent i from being overridden in this case?

too honest for this site
  • 12,050
  • 4
  • 30
  • 52
Cyker
  • 9,946
  • 8
  • 65
  • 93
  • 2
    In C, you can create a block and declare a new instance of the variable in that block. In Python, you could create a nested function and define the variable within that function, then call the function from within the parent. – Tom Karzes Mar 12 '16 at 06:33
  • 3
    idenpendently of the whole issue of overriding, why not use a different var name? its not like you only a certain amount – Mixone Mar 12 '16 at 06:59
  • Have a look on this http://stackoverflow.com/questions/291978/short-description-of-python-scoping-rules – SUDARSHAN BHALERAO Mar 12 '16 at 07:02
  • its just that both the i in c code are saved and used as different varaibles saved at different localities , having different scopes , the interior i has a loop scope so... my key of advice is the same as that of @Mixone why you want to have same variable...it would rather make your work more worse in a long go... evaluating that which variable scope ends where and which one is currently being used...instead use another variable – Shreyan Mehta Mar 12 '16 at 08:36
  • @TomKarzes Your comment reminds me of the classic JavaScript for loop bug and it's solved by opening a new function and calling it afterwards. Not sure whether Python can do better. – Cyker Mar 12 '16 at 09:01
  • @Mixone It's better if you have a lot of free variables to use. But sometimes you have nested loops, or loops after loops. In almost all cases it's good to know different parts of your program don't interfere with each other. If a variable should be short-lived, then it should be short-lived. – Cyker Mar 12 '16 at 09:09
  • well i personally use naming conventions, I try to avoid things like a var named i only – Mixone Mar 12 '16 at 09:30

3 Answers3

2

That has to do with scope. In the example in C that you listed, int i = 0 is inside the for loop scope(that 'i' in particular is a local member of that forloop. It's not that 'i' isn't being overwritten, it's that they're in 2 different localities, so they aren't related to one another at all(other than visually when you look at it).

Python scope: Short Description of the Scoping Rules?

Community
  • 1
  • 1
Ryan G
  • 380
  • 1
  • 11
  • Yes I agree with you. I know scopes and I wrote this question to see if anyone has an elegant way to open a new scope in Python for this specific task. – Cyker Mar 12 '16 at 08:58
1

You have to put the loop into a new scope. One way to do that is to use a function. Another way is to put it into a generator expression:

i = 3
a = min((i-10)**2 for i in range(5))
print(a, i)

output

36 3

Another option in Python 3 is to put the loop into a list comprehension, but in Python 2 that does not create a new scope (for efficiency reasons).

i = 3
a = min([(i-10)**2 for i in range(5)])
print a, i

output

36 4

That list comp isn't as efficient as the generator expression above: it uses more RAM, and min has to wait for the full list to be constructed, whereas in the generator expression version it can start processing values yielded by the gen exp straight away.

PM 2Ring
  • 54,345
  • 6
  • 82
  • 182
  • The list comprehension you pointed out is a good example of the difference between Python 2 and 3 (or called a bug of Python 2). I like using generator expression and list comprehension as you wrote here. But if the loop body has a non-trivial size then a for loop still have to be used. But I'm not aware of any *Pythonic* way of doing this using the same variable name. – Cyker Mar 12 '16 at 08:55
  • @Cyker: I wouldn't call it a bug, but I agree it _is_ natural to assume that a list comp would create a new scope. If the size is non-trivial then you should format the list comp over multiple lines, or if it's deeply nested break it up into separate list comps. Also, a list comp isn't a general substitute for a `for` loop. Eg, using a list comp purely for side-effects where you immediately discard the resulting list is un-Pythonic. – PM 2Ring Mar 13 '16 at 18:01
1

I suggest that using the same name to refer to different variables in the same function is bad practice. Even in C. There are plenty of other bad practices in C that you can't do in python, for example failing to indent.

My point is that the C case is undesirable. I concede that this is acceptable:

for (int i = 0; i < 42; i++) { ... }

for (int i = 0; i < 37; i++) { ... }

But having an outer version of i as well would be confusing.

Those kinds of loops are mostly used in C for iterating through arrays. In the example i is an int, but it could be a pointer that is being incremented.

Counting loops using range() are not needed nearly as much in python because we have object iterators.

A frustrated C programmer might do this in python:

for i in range(len(mylist)):
    print(mylist[i])

but the following is preferred:

for list_item in mylist:
    print(list_item)

So my second point is that the C case is unnecessary.

The philosophy in Python is based on objects and object iterators. In C you don't have that. In C myarray[i] is syntactic sugar for *(myarray + i), we just don't want that in python, we have many more different types of containers than C and iteration should be consistent.

I'm not saying you never need the index number, but there is always enumerate().

cdarke
  • 42,728
  • 8
  • 80
  • 84