[Tutor] list comprehensions isolate variables but for loops don't - is there a special usage?

Oscar Benjamin oscar.j.benjamin at gmail.com
Wed Jun 5 11:29:55 CEST 2013


On 5 June 2013 06:53, Jim Mooney <cybervigilante at gmail.com> wrote:
> I just noticed that a list comprehension doesn't change a same-name
> variable outside of it, but a for loop does. That is:
>
> #Using Python 3.3.2 on Win 7

In this case the version is relevant since this behaviour changed in
Python 3.x as others have pointed out. I just want to add that the
reason for the change is that it's easier to accidentally bind a name
when using list comprehensions than with a for loop.

With a for loop the name being bound appears prominently at the start
of the line e.g.:

  for x in func1(arg1, arg2, param1=val1, param2=val2):
      print(func3(stuff, x))

However in a list comprehension you might do something like:

  x = 2*y
  z = long_function_name('qwe',
                         param1=func2('foo'),
                         param2=[x for x in func3('bar')],
                         param3='foobar')
  print(x, z)

In this case it's less obvious that you're binding to the name 'x' (in
Python 2.x). I've definitely made this mistake before. I don't think
it ever went unnoticed in my own code but it could easily lead to a
subtle and hard to spot bug.

Generally in Python binding names is done very explicitly and it is
easy to see from the code when names are bound which is a good thing.
There are hacky exceptions to this using e.g. globals() or
sys._getframe() and the like but if you stick to normal Python code
names do not get bound unexpectedly.

If you want to access the loop variable from a list comprehension you could use:

  values = [x for x in stuff]
  print(values[-1])

This is not necessarily the same if the list comp has an if clause but
otherwise it gives you the same value (and raises an error in the same
situations).


Oscar


More information about the Tutor mailing list