Variable in a for loop affects the global variable [duplicate] - python

I'm not asking about Python's scoping rules; I understand generally how scoping works in Python for loops. My question is why the design decisions were made in this way. For example (no pun intended):
for foo in xrange(10):
bar = 2
print(foo, bar)
The above will print (9,2).
This strikes me as weird: 'foo' is really just controlling the loop, and 'bar' was defined inside the loop. I can understand why it might be necessary for 'bar' to be accessible outside the loop (otherwise, for loops would have very limited functionality). What I don't understand is why it is necessary for the control variable to remain in scope after the loop exits. In my experience, it simply clutters the global namespace and makes it harder to track down errors that would be caught by interpreters in other languages.

The likeliest answer is that it just keeps the grammar simple, hasn't been a stumbling block for adoption, and many have been happy with not having to disambiguate the scope to which a name belongs when assigning to it within a loop construct. Variables are not declared within a scope, it is implied by the location of assignment statements. The global keyword exists just for this reason (to signify that assignment is done at a global scope).
Update
Here's a good discussion on the topic: http://mail.python.org/pipermail/python-ideas/2008-October/002109.html
Previous proposals to make for-loop
variables local to the loop have
stumbled on the problem of existing
code that relies on the loop variable
keeping its value after exiting the
loop, and it seems that this is
regarded as a desirable feature.
In short, you can probably blame it on the Python community :P

Python does not have blocks, as do some other languages (such as C/C++ or Java). Therefore, scoping unit in Python is a function.

A really useful case for this is when using enumerate and you want the total count in the end:
for count, x in enumerate(someiterator, start=1):
dosomething(count, x)
print "I did something {0} times".format(count)
Is this necessary? No. But, it sure is convenient.
Another thing to be aware of: in Python 2, variables in list comprehensions are leaked as well:
>>> [x**2 for x in range(10)]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> x
9
But, the same does not apply to Python 3.

One of the primary influences for Python is ABC, a language developed in the Netherlands for teaching programming concepts to beginners. Python's creator, Guido van Rossum, worked on ABC for several years in the 1980s. I know almost nothing about ABC, but as it is intended for beginners, I suppose it must have a limited number of scopes, much like early BASICs.

If you have a break statement in the loop (and want to use the iteration value later, perhaps to pick back up, index something, or give status), it saves you one line of code and one assignment, so there's a convenience.

It is a design choice in Python, which often makes some tasks easier than in other languages with the typical block scope behavior.
But oftentimes you would still miss the typical block scopes, because, say, you might have large temporary arrays which should be freed as soon as possible. It could be done by temporary function/class tricks but still there is a neater solution achieved with directly manipulating the interpreter state.
from scoping import scoping
a = 2
with scoping():
assert(2 == a)
a = 3
b = 4
scoping.keep('b')
assert(3 == a)
assert(2 == a)
assert(4 == b)
https://github.com/l74d/scoping

I might be wrong, but if I am certain that I don't need to access foo outside the loop, I would write it in this way
for _foo in xrange(10):
bar = 2

For starters, if variables were local to loops, those loops would be useless for most real-world programming.
In the current situation:
# Sum the values 0..9
total = 0
for foo in xrange(10):
total = total + foo
print total
yields 45. Now, consider how assignment works in Python. If loop variables were strictly local:
# Sum the values 0..9?
total = 0
for foo in xrange(10):
# Create a new integer object with value "total + foo" and bind it to a new
# loop-local variable named "total".
total = total + foo
print total
yields 0, because total inside the loop after the assignment is not the same variable as total outside the loop. This would not be optimal or expected behavior.

Related

python local variable still accessible outside of 'scope' [duplicate]

I'm not asking about Python's scoping rules; I understand generally how scoping works in Python for loops. My question is why the design decisions were made in this way. For example (no pun intended):
for foo in xrange(10):
bar = 2
print(foo, bar)
The above will print (9,2).
This strikes me as weird: 'foo' is really just controlling the loop, and 'bar' was defined inside the loop. I can understand why it might be necessary for 'bar' to be accessible outside the loop (otherwise, for loops would have very limited functionality). What I don't understand is why it is necessary for the control variable to remain in scope after the loop exits. In my experience, it simply clutters the global namespace and makes it harder to track down errors that would be caught by interpreters in other languages.
The likeliest answer is that it just keeps the grammar simple, hasn't been a stumbling block for adoption, and many have been happy with not having to disambiguate the scope to which a name belongs when assigning to it within a loop construct. Variables are not declared within a scope, it is implied by the location of assignment statements. The global keyword exists just for this reason (to signify that assignment is done at a global scope).
Update
Here's a good discussion on the topic: http://mail.python.org/pipermail/python-ideas/2008-October/002109.html
Previous proposals to make for-loop
variables local to the loop have
stumbled on the problem of existing
code that relies on the loop variable
keeping its value after exiting the
loop, and it seems that this is
regarded as a desirable feature.
In short, you can probably blame it on the Python community :P
Python does not have blocks, as do some other languages (such as C/C++ or Java). Therefore, scoping unit in Python is a function.
A really useful case for this is when using enumerate and you want the total count in the end:
for count, x in enumerate(someiterator, start=1):
dosomething(count, x)
print "I did something {0} times".format(count)
Is this necessary? No. But, it sure is convenient.
Another thing to be aware of: in Python 2, variables in list comprehensions are leaked as well:
>>> [x**2 for x in range(10)]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> x
9
But, the same does not apply to Python 3.
One of the primary influences for Python is ABC, a language developed in the Netherlands for teaching programming concepts to beginners. Python's creator, Guido van Rossum, worked on ABC for several years in the 1980s. I know almost nothing about ABC, but as it is intended for beginners, I suppose it must have a limited number of scopes, much like early BASICs.
If you have a break statement in the loop (and want to use the iteration value later, perhaps to pick back up, index something, or give status), it saves you one line of code and one assignment, so there's a convenience.
It is a design choice in Python, which often makes some tasks easier than in other languages with the typical block scope behavior.
But oftentimes you would still miss the typical block scopes, because, say, you might have large temporary arrays which should be freed as soon as possible. It could be done by temporary function/class tricks but still there is a neater solution achieved with directly manipulating the interpreter state.
from scoping import scoping
a = 2
with scoping():
assert(2 == a)
a = 3
b = 4
scoping.keep('b')
assert(3 == a)
assert(2 == a)
assert(4 == b)
https://github.com/l74d/scoping
I might be wrong, but if I am certain that I don't need to access foo outside the loop, I would write it in this way
for _foo in xrange(10):
bar = 2
For starters, if variables were local to loops, those loops would be useless for most real-world programming.
In the current situation:
# Sum the values 0..9
total = 0
for foo in xrange(10):
total = total + foo
print total
yields 45. Now, consider how assignment works in Python. If loop variables were strictly local:
# Sum the values 0..9?
total = 0
for foo in xrange(10):
# Create a new integer object with value "total + foo" and bind it to a new
# loop-local variable named "total".
total = total + foo
print total
yields 0, because total inside the loop after the assignment is not the same variable as total outside the loop. This would not be optimal or expected behavior.

Does deleting a variable in python for loop make it more memory efficient?

Let's say that I have a variable in which I will use for a loop 1000 times such that:
A = [3,4,5,6]
for i in range(1000):
# if something
# c = <a list which length depends on runtime>
A = c
del c
Would deleting c after single loop makes memory consumption more efficient?
In general, no. It doesn't.
del deletes names from namespaces, not objects.
Of course, if you remove a reference, and the reference count reaches 0, the object will be reclaimed (immediately in CPython).
But note, in your loop above, you create another reference anyway, A = c, so it definitely doesn't help at all.
There is one scenario where this may be beneficial, suppose you do this in a global scope, e.g. at a module level, so not in a function. Because python for-loops don't create their own scopes, c has now remained in the global namespace, and potentially, it keeps a giant list alive until the end of the program.
This is usually better solved by organizing your program better into modular functions, and only creating references to objects in the global scope that you want to survive until the end of the program. However, sometimes, you do end up doing a loop like that, and in that case, explicitly removing that last reference does help (but again, since you did A = c, then it wouldn't help anyway).
I feel that you have a fundamental misunderstanding of how Python variables work. I second the suggestion from the comments to read:
https://nedbatchelder.com/text/names.html

Does functional programming allow mutability of locally scoped objects?

I learnt that mutability of an object is defined with respect to its state but not with its identity.
Below program changes state of a locally scoped object referred by name count within function hailstone().
def hailstone(n):
count = 1
"""Print the terms of the 'hailstone sequence' from n to 1."""
assert n > 0
print(n)
if n > 1:
if n % 2 == 0:
count += hailstone(n / 2)
else:
count += hailstone((n * 3) + 1)
return count
if (__name__ == '__main__'):
result = hailstone(10)
print(result)
After reading the below paragraph of this article, I see that the above code looks fine as regards changing the state of the locally scoped object that name count refers to (i.e. count += hailstone(n / 2)):
Ignore all that. Functional code is characterised by one thing: the absence of side effects. It doesn't rely on data outside the current function, and it doesn't change data that exists outside the current function. Every other “functional” thing can be derived from this property. Use it as a guide rope as you learn.
So, how do I understand the meaning of this statement from this answer:
In functional programming, it is not proper to ever change the value of a variable.
Does functional programming allow changing the state of the locally scoped object referred by name count in my above program?
There is no clearcut definition of functional programming. However, it typically is meant to imply the absence, or at least the minimisation, of side effects -- sometimes people speak of pure functional programming to emphasise their complete absence. But what is a side effect?
A common definition is that a side effect is anything that breaks referential transparency. Referential transparency in turn can be defined in various ways, but perhaps the most enlightening definition is that order of evaluation should be irrelevant. That is, a program is referentially transparent (or pure) if you can simplify any of its subexpressions, in any order, merely by substituting definitions, without changing the outcome of the program. In particular, you can always replace a variable with its (unique!) definition.
Clearly, an assignments to a mutable variable breaks this condition, so it has to be considered a side effect -- even if it is merely local. Likewise a print statement, by the way.
There are ways to have mutable state, or IO, without breaking referential transparency. That is the mystical concept of a monad. But I won't go into that here.
Not knowing Python, I assume count is a "local" variable, not visible from outside, and every invokation of hailstone gets its own instance of count. If this is so, then, as #jonrsharpe explained, it is immaterial what you do to count.
Observe, however, that your code is needlessly verbose. Why not simply:
if n > 1:
if n % 2 == 0:
return 1 + hailstone(n/2)
else:
return 1 + hailstone(n*3+1)
else:
return 1
It turns out that the variable is not needed at all, not to speak of the need to update it.
Your function has no side effects (aside from the print) at the function level. That's a necessary, but not sufficient, condition to be called functional. Functional programs consist of one big expression. Your example is expressions at the function level, interspersed with imperative statements in the function body. An if without an else is a statement, as is a variable reassignment.
That's not to say that an imperative function without side effects isn't better than an imperative function with side effects. There are certainly advantages to your example, even if it isn't considered purely functional.
This program mutates x:
x = 2
x = x * 3
x = x + 4
return x
In functional programming you don't use mutation. Your code should define each variable exactly once:
x1 = 2
x2 = x1 * 3
x3 = x2 + 4
return x3
It is possible that the compiler will allocate the same memory location for x1, x2 and x3, and mutate in place, as the original program does. However, this is an implementation detail and shouldn't be important.
Unlike the previous sequential program, you can think of the new one as a system of equations and read it in arbitrary order. In this case the computation still has to be done top-to-bottom due to data dependency, but this does not have to in general.
You can get rid of the "=" symbol altogether, by using functions. To get rid of "x1 = 2", parametrize the remaining lines by x1 and pass 2 to the function:
(function(x1) {
x2 = x1 * 3
x3 = x2 + 4
return x3
})(2)
and continue this process to remove "x2 = x1 * 3" and "x3 = x2 * 4".
Sometimes you assign to a variable in a loop to accumulate something (e.g. add items in an array for x in A: sum += x). In this case, instead of repeated assignment you can rewrite the program to use functions such as "sum", "reduce", "map", "filter", which are high-level abstractions of loops.
I was lying. It is possible to have local mutable state in a pure functional program, as long as the mutability does not "leak" outside of the scope. In Haskell, there is a library called "ST" for this purpose. It embeds a small imperative language with commands 'create variable', 'read variable', 'write variable', and if your program does not leak a mutable variable, you can retrieve its result in a pure function. However, it is more awkward to use (see this answer) and not used as much as you use assignment in imperative languages.

Why are there no ++ and --​ operators in Python?

Why are there no ++ and -- operators in Python?
It's not because it doesn't make sense; it makes perfect sense to define "x++" as "x += 1, evaluating to the previous binding of x".
If you want to know the original reason, you'll have to either wade through old Python mailing lists or ask somebody who was there (eg. Guido), but it's easy enough to justify after the fact:
Simple increment and decrement aren't needed as much as in other languages. You don't write things like for(int i = 0; i < 10; ++i) in Python very often; instead you do things like for i in range(0, 10).
Since it's not needed nearly as often, there's much less reason to give it its own special syntax; when you do need to increment, += is usually just fine.
It's not a decision of whether it makes sense, or whether it can be done--it does, and it can. It's a question of whether the benefit is worth adding to the core syntax of the language. Remember, this is four operators--postinc, postdec, preinc, predec, and each of these would need to have its own class overloads; they all need to be specified, and tested; it would add opcodes to the language (implying a larger, and therefore slower, VM engine); every class that supports a logical increment would need to implement them (on top of += and -=).
This is all redundant with += and -=, so it would become a net loss.
This original answer I wrote is a myth from the folklore of computing: debunked by Dennis Ritchie as "historically impossible" as noted in the letters to the editors of Communications of the ACM July 2012 doi:10.1145/2209249.2209251
The C increment/decrement operators were invented at a time when the C compiler wasn't very smart and the authors wanted to be able to specify the direct intent that a machine language operator should be used which saved a handful of cycles for a compiler which might do a
load memory
load 1
add
store memory
instead of
inc memory
and the PDP-11 even supported "autoincrement" and "autoincrement deferred" instructions corresponding to *++p and *p++, respectively. See section 5.3 of the manual if horribly curious.
As compilers are smart enough to handle the high-level optimization tricks built into the syntax of C, they are just a syntactic convenience now.
Python doesn't have tricks to convey intentions to the assembler because it doesn't use one.
I always assumed it had to do with this line of the zen of python:
There should be one — and preferably only one — obvious way to do it.
x++ and x+=1 do the exact same thing, so there is no reason to have both.
Of course, we could say "Guido just decided that way", but I think the question is really about the reasons for that decision. I think there are several reasons:
It mixes together statements and expressions, which is not good practice. See http://norvig.com/python-iaq.html
It generally encourages people to write less readable code
Extra complexity in the language implementation, which is unnecessary in Python, as already mentioned
Because, in Python, integers are immutable (int's += actually returns a different object).
Also, with ++/-- you need to worry about pre- versus post- increment/decrement, and it takes only one more keystroke to write x+=1. In other words, it avoids potential confusion at the expense of very little gain.
Clarity!
Python is a lot about clarity and no programmer is likely to correctly guess the meaning of --a unless s/he's learned a language having that construct.
Python is also a lot about avoiding constructs that invite mistakes and the ++ operators are known to be rich sources of defects.
These two reasons are enough not to have those operators in Python.
The decision that Python uses indentation to mark blocks rather
than syntactical means such as some form of begin/end bracketing
or mandatory end marking is based largely on the same considerations.
For illustration, have a look at the discussion around introducing a conditional operator (in C: cond ? resultif : resultelse) into Python in 2005.
Read at least the first message and the decision message of that discussion (which had several precursors on the same topic previously).
Trivia:
The PEP frequently mentioned therein is the "Python Enhancement Proposal" PEP 308. LC means list comprehension, GE means generator expression (and don't worry if those confuse you, they are none of the few complicated spots of Python).
My understanding of why python does not have ++ operator is following: When you write this in python a=b=c=1 you will get three variables (labels) pointing at same object (which value is 1). You can verify this by using id function which will return an object memory address:
In [19]: id(a)
Out[19]: 34019256
In [20]: id(b)
Out[20]: 34019256
In [21]: id(c)
Out[21]: 34019256
All three variables (labels) point to the same object. Now increment one of variable and see how it affects memory addresses:
In [22] a = a + 1
In [23]: id(a)
Out[23]: 34019232
In [24]: id(b)
Out[24]: 34019256
In [25]: id(c)
Out[25]: 34019256
You can see that variable a now points to another object as variables b and c. Because you've used a = a + 1 it is explicitly clear. In other words you assign completely another object to label a. Imagine that you can write a++ it would suggest that you did not assign to variable a new object but ratter increment the old one. All this stuff is IMHO for minimization of confusion. For better understanding see how python variables works:
In Python, why can a function modify some arguments as perceived by the caller, but not others?
Is Python call-by-value or call-by-reference? Neither.
Does Python pass by value, or by reference?
Is Python pass-by-reference or pass-by-value?
Python: How do I pass a variable by reference?
Understanding Python variables and Memory Management
Emulating pass-by-value behaviour in python
Python functions call by reference
Code Like a Pythonista: Idiomatic Python
It was just designed that way. Increment and decrement operators are just shortcuts for x = x + 1. Python has typically adopted a design strategy which reduces the number of alternative means of performing an operation. Augmented assignment is the closest thing to increment/decrement operators in Python, and they weren't even added until Python 2.0.
I'm very new to python but I suspect the reason is because of the emphasis between mutable and immutable objects within the language. Now, I know that x++ can easily be interpreted as x = x + 1, but it LOOKS like you're incrementing in-place an object which could be immutable.
Just my guess/feeling/hunch.
To complete already good answers on that page:
Let's suppose we decide to do this, prefix (++i) that would break the unary + and - operators.
Today, prefixing by ++ or -- does nothing, because it enables unary plus operator twice (does nothing) or unary minus twice (twice: cancels itself)
>>> i=12
>>> ++i
12
>>> --i
12
So that would potentially break that logic.
now if one needs it for list comprehensions or lambdas, from python 3.8 it's possible with the new := assignment operator (PEP572)
pre-incrementing a and assign it to b:
>>> a = 1
>>> b = (a:=a+1)
>>> b
2
>>> a
2
post-incrementing just needs to make up the premature add by subtracting 1:
>>> a = 1
>>> b = (a:=a+1)-1
>>> b
1
>>> a
2
I believe it stems from the Python creed that "explicit is better than implicit".
First, Python is only indirectly influenced by C; it is heavily influenced by ABC, which apparently does not have these operators, so it should not be any great surprise not to find them in Python either.
Secondly, as others have said, increment and decrement are supported by += and -= already.
Third, full support for a ++ and -- operator set usually includes supporting both the prefix and postfix versions of them. In C and C++, this can lead to all kinds of "lovely" constructs that seem (to me) to be against the spirit of simplicity and straight-forwardness that Python embraces.
For example, while the C statement while(*t++ = *s++); may seem simple and elegant to an experienced programmer, to someone learning it, it is anything but simple. Throw in a mixture of prefix and postfix increments and decrements, and even many pros will have to stop and think a bit.
The ++ class of operators are expressions with side effects. This is something generally not found in Python.
For the same reason an assignment is not an expression in Python, thus preventing the common if (a = f(...)) { /* using a here */ } idiom.
Lastly I suspect that there operator are not very consistent with Pythons reference semantics. Remember, Python does not have variables (or pointers) with the semantics known from C/C++.
as i understood it so you won't think the value in memory is changed.
in c when you do x++ the value of x in memory changes.
but in python all numbers are immutable hence the address that x pointed as still has x not x+1. when you write x++ you would think that x change what really happens is that x refrence is changed to a location in memory where x+1 is stored or recreate this location if doe's not exists.
Other answers have described why it's not needed for iterators, but sometimes it is useful when assigning to increase a variable in-line, you can achieve the same effect using tuples and multiple assignment:
b = ++a becomes:
a,b = (a+1,)*2
and b = a++ becomes:
a,b = a+1, a
Python 3.8 introduces the assignment := operator, allowing us to achievefoo(++a) with
foo(a:=a+1)
foo(a++) is still elusive though.
Maybe a better question would be to ask why do these operators exist in C. K&R calls increment and decrement operators 'unusual' (Section 2.8page 46). The Introduction calls them 'more concise and often more efficient'. I suspect that the fact that these operations always come up in pointer manipulation also has played a part in their introduction.
In Python it has been probably decided that it made no sense to try to optimise increments (in fact I just did a test in C, and it seems that the gcc-generated assembly uses addl instead of incl in both cases) and there is no pointer arithmetic; so it would have been just One More Way to Do It and we know Python loathes that.
This may be because #GlennMaynard is looking at the matter as in comparison with other languages, but in Python, you do things the python way. It's not a 'why' question. It's there and you can do things to the same effect with x+=. In The Zen of Python, it is given: "there should only be one way to solve a problem." Multiple choices are great in art (freedom of expression) but lousy in engineering.
I think this relates to the concepts of mutability and immutability of objects. 2,3,4,5 are immutable in python. Refer to the image below. 2 has fixed id until this python process.
x++ would essentially mean an in-place increment like C. In C, x++ performs in-place increments. So, x=3, and x++ would increment 3 in the memory to 4, unlike python where 3 would still exist in memory.
Thus in python, you don't need to recreate a value in memory. This may lead to performance optimizations.
This is a hunch based answer.
I know this is an old thread, but the most common use case for ++i is not covered, that being manually indexing sets when there are no provided indices. This situation is why python provides enumerate()
Example : In any given language, when you use a construct like foreach to iterate over a set - for the sake of the example we'll even say it's an unordered set and you need a unique index for everything to tell them apart, say
i = 0
stuff = {'a': 'b', 'c': 'd', 'e': 'f'}
uniquestuff = {}
for key, val in stuff.items() :
uniquestuff[key] = '{0}{1}'.format(val, i)
i += 1
In cases like this, python provides an enumerate method, e.g.
for i, (key, val) in enumerate(stuff.items()) :
In addition to the other excellent answers here, ++ and -- are also notorious for undefined behavior. For example, what happens in this code?
foo[bar] = bar++;
It's so innocent-looking, but it's wrong C (and C++), because you don't know whether the first bar will have been incremented or not. One compiler might do it one way, another might do it another way, and a third might make demons fly out of your nose. All would be perfectly conformant with the C and C++ standards.
(EDIT: C++17 has changed the behavior of the given code so that it is defined; it will be equivalent to foo[bar+1] = bar; ++bar; — which nonetheless might not be what the programmer is expecting.)
Undefined behavior is seen as a necessary evil in C and C++, but in Python, it's just evil, and avoided as much as possible.

Scoping in Python 'for' loops

I'm not asking about Python's scoping rules; I understand generally how scoping works in Python for loops. My question is why the design decisions were made in this way. For example (no pun intended):
for foo in xrange(10):
bar = 2
print(foo, bar)
The above will print (9,2).
This strikes me as weird: 'foo' is really just controlling the loop, and 'bar' was defined inside the loop. I can understand why it might be necessary for 'bar' to be accessible outside the loop (otherwise, for loops would have very limited functionality). What I don't understand is why it is necessary for the control variable to remain in scope after the loop exits. In my experience, it simply clutters the global namespace and makes it harder to track down errors that would be caught by interpreters in other languages.
The likeliest answer is that it just keeps the grammar simple, hasn't been a stumbling block for adoption, and many have been happy with not having to disambiguate the scope to which a name belongs when assigning to it within a loop construct. Variables are not declared within a scope, it is implied by the location of assignment statements. The global keyword exists just for this reason (to signify that assignment is done at a global scope).
Update
Here's a good discussion on the topic: http://mail.python.org/pipermail/python-ideas/2008-October/002109.html
Previous proposals to make for-loop
variables local to the loop have
stumbled on the problem of existing
code that relies on the loop variable
keeping its value after exiting the
loop, and it seems that this is
regarded as a desirable feature.
In short, you can probably blame it on the Python community :P
Python does not have blocks, as do some other languages (such as C/C++ or Java). Therefore, scoping unit in Python is a function.
A really useful case for this is when using enumerate and you want the total count in the end:
for count, x in enumerate(someiterator, start=1):
dosomething(count, x)
print "I did something {0} times".format(count)
Is this necessary? No. But, it sure is convenient.
Another thing to be aware of: in Python 2, variables in list comprehensions are leaked as well:
>>> [x**2 for x in range(10)]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> x
9
But, the same does not apply to Python 3.
One of the primary influences for Python is ABC, a language developed in the Netherlands for teaching programming concepts to beginners. Python's creator, Guido van Rossum, worked on ABC for several years in the 1980s. I know almost nothing about ABC, but as it is intended for beginners, I suppose it must have a limited number of scopes, much like early BASICs.
If you have a break statement in the loop (and want to use the iteration value later, perhaps to pick back up, index something, or give status), it saves you one line of code and one assignment, so there's a convenience.
It is a design choice in Python, which often makes some tasks easier than in other languages with the typical block scope behavior.
But oftentimes you would still miss the typical block scopes, because, say, you might have large temporary arrays which should be freed as soon as possible. It could be done by temporary function/class tricks but still there is a neater solution achieved with directly manipulating the interpreter state.
from scoping import scoping
a = 2
with scoping():
assert(2 == a)
a = 3
b = 4
scoping.keep('b')
assert(3 == a)
assert(2 == a)
assert(4 == b)
https://github.com/l74d/scoping
I might be wrong, but if I am certain that I don't need to access foo outside the loop, I would write it in this way
for _foo in xrange(10):
bar = 2
For starters, if variables were local to loops, those loops would be useless for most real-world programming.
In the current situation:
# Sum the values 0..9
total = 0
for foo in xrange(10):
total = total + foo
print total
yields 45. Now, consider how assignment works in Python. If loop variables were strictly local:
# Sum the values 0..9?
total = 0
for foo in xrange(10):
# Create a new integer object with value "total + foo" and bind it to a new
# loop-local variable named "total".
total = total + foo
print total
yields 0, because total inside the loop after the assignment is not the same variable as total outside the loop. This would not be optimal or expected behavior.

Categories

Resources