[Tutor] Would somebody kindly...

Steven D'Aprano steve at pearwood.info
Fri Oct 31 01:09:08 CET 2014


On Wed, Oct 29, 2014 at 10:39:53PM -0700, Clayton Kirkwood wrote:

> When you have 
> [item for item in [list] if item[0] == key], after the iteration 
> completes does item equal the matched entities or does it have the 
> original item?

Why don't you try it for yourself and find out? At the interactive 
interpreter -- do you know how to run the interactive interpreter? if 
not, you should ask -- simply try it:

py> key = 23
py> result = [item for item in [(20, 1), (21, 2), (23, 4)] if item[0] == key]
py> print(item)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'item' is not defined


So in Python 3, the list comprehension variable `item` is *not* visible 
outside of the list comprehension. If we set a variable `item` ahead of 
time, then try it again, we'll see that it is not changed.

py> item = "something"
py> result = [item for item in [(20, 1), (21, 2), (23, 4)] if item[0] == key]
py> print(item)
something


[Note: this is different from Python 2, where the list comprehension 
variable "leaks" outside of the comprehension. That was considered an 
accident, if not a bug, and fixed in Python 3.]


What is happening here? This may not be *exactly* what Python does, but 
it will give you a reasonable idea of how list comprehensions work. When 
you write something like:

result = [2*x + 1 for x in sequence if condition(x)]

the Python compiler builds a hidden function:

def _list_comp():
    tmp = []
    for x in sequence:
         if condition(x):
             tmp.append(2*x + 1)
    return tmp

then executes it:

result = _list_comp()

(except that the hidden function is completely invisible to Python code, 
only the compiler can access it).

So you can see that the list comp variable x is a local variable, 
localised to the list comprehension, and doesn't change any existing x 
outside of the list comprehension.


> This is from a previous email--
> When I run:
> values = [ ('a', 1), ('b', 2), ('a', 5), ('c', 7)]
> key = 'a'
> pair=[]
> [pair for pair in values if key == pair[0]]
> print(pair)
> 
> I get [].


Correct. The result of the list comprehension [pair for ...] is built, 
then thrown away because you don't do anything with it. The existing 
variable `pair` is unchanged, since the `pair` inside the list comp 
lives inside it's own scope, separate from the outside `pair`. This is 
no different from this situation:

pair = 'something'  # global scope

def f():
    pair = 23  # local to function f

def g():
    pair = 42  # local to function g

[pair for pair in sequence]  # local to list comp


In this case, there are four *different* `pair` variables, different 
because they live in different scopes.

> When I run:
> values = [ ('a', 1), ('b', 2), ('a', 5), ('c', 7)]
> key = 'a'
> pair=[]
> x=[pair for pair in values if key == pair[0]]
> print(x)
> 
> I get [('a', 1), ('a', 5)]

That's because you build the list, and instead of throwing it away, you 
assign it to the variable `x`, then print `x`. The variable `pair` 
remains unchanged.



-- 
Steven


More information about the Tutor mailing list