for x in... x remains global

  • Thread starter Antoine De Groote
  • Start date
A

Antoine De Groote

for x in range(3): pass

After this statement is executed x is global variable. This seems very
unnatural to me and caused me 3 three days of debugging because I was
unintentionally using x further down in my program (typo). I would have
thought that variables like this are local to the for block.

Is there a reason this is not the case? Maybe there are PEPs or
something else about the matter that you can point me to?

Regards,
antoine
 
D

Diez B. Roggisch

Antoine said:
for x in range(3): pass

After this statement is executed x is global variable. This seems very
unnatural to me and caused me 3 three days of debugging because I was
unintentionally using x further down in my program (typo). I would have
thought that variables like this are local to the for block.

Is there a reason this is not the case? Maybe there are PEPs or
something else about the matter that you can point me to?

It's an somewhat unfortunate fact that loop variables leak to the outer
scope. List-comps as well, btw.

In

http://www.python.org/dev/peps/pep-0289/

it says that this will be remedied in Py3K

"""
List comprehensions also "leak" their loop variable into the surrounding
scope. This will also change in Python 3.0, so that the semantic definition
of a list comprehension in Python 3.0 will be equivalent to list(<generator
expression>). Python 2.4 and beyond should issue a deprecation warning if a
list comprehension's loop variable has the same name as a variable used in
the immediately surrounding scope.
"""

And while I can't make an authorative statement about this, I can imagine
that it won't be fixed anywhere in python2.X, as code like this is
certainly to be found:

for x in some_xes:
if condition(x):
break

print x


Diez
 
D

Duncan Booth

Antoine De Groote said:
for x in range(3): pass

After this statement is executed x is global variable. This seems very
unnatural to me and caused me 3 three days of debugging because I was
unintentionally using x further down in my program (typo). I would have
thought that variables like this are local to the for block.

Blocks in Python never create new scopes. You have global variables for
each module and one set of local variables for each function. There is a
minor exception in that the control variables in generator expressions are
in a separate scope, but variables are never local to a block.
Is there a reason this is not the case? Maybe there are PEPs or
something else about the matter that you can point me to?

One good reason is that sometimes you want to use the loop variable after
the end of the loop:

for x in somesequence:
if somecondition(x):
break
else:
raise NotFoundError
print "found", x

Try to write lots of small functions and then you can keep the scope of
variables suitably small.
 
B

Ben Finney

Antoine De Groote said:
for x in range(3): pass

After this statement is executed x is global variable.

Not exactly. The name 'x' is bound at the scope of the 'for'
statement, and remains bound after the 'for' statement stops, just as
it would be if it was bound in any other statement.
This seems very unnatural to me and caused me 3 three days of
debugging because I was unintentionally using x further down in my
program (typo).

This is, when used intentionally, one of the main useful features of
this behaviour: to determine where an iteration stopped by using the
value bound to the name ('x' in this case) after the iteration
statement.
I would have thought that variables like this are local to the for
block.

They're bound at the scope of the 'for' statement. They're available
inside the suite of that statement.
Is there a reason this is not the case? Maybe there are PEPs or
something else about the matter that you can point me to?

This message addresses it:

<URL:http://mail.python.org/pipermail/python-dev/2006-April/064624.html>

A search for the separate terms "python iteration variable scope" will
turn up more.
 
S

skip

Diez> It's an somewhat unfortunate fact that loop variables leak to the
Diez> outer scope. List-comps as well, btw.

It's unfortunate that loop variables leak from list comprehensions (they
don't leak in genexps). It's by design in for loops though. Consider:

for i in range(10):
if i*i == 9:
break
print i

In this silly example, the loop index is the useful value of the
computation. You could assign to a different variable, though that would be
slightly ugly:

for i in range(10:
j = i
if j*j == 9:
break
print j

Skip
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,581
Members
45,056
Latest member
GlycogenSupporthealth

Latest Threads

Top