Re: [Tutor] Strange behaviour of list comprehension

2013-02-13 Thread Oscar Benjamin
On 13 February 2013 13:45, Mahadevan, Anand maha...@labcorp.com wrote:
 I'm playing around with list comprehension and in IDLE typed this in.  I 
 actually wanted it to return all tuples satisfying the condition where z is 
 the sum of x and y. I kind of got mixed up with the syntax, hence I put a 
 comma in there instead of an if.  I'd like some assistance understanding 
 what it's doing...
 Thanks!

 somelist = [(x,y,z) for x in range(1,10) for y in range(x,10) for z in 
 range(y,10), x+y==z]

This line doesn't actually work if you paste it into a fresh interpreter:
 somelist = [(x,y,z) for x in range(1,10) for y in range(x,10) for z in 
 range(y,10), x+y==z]
Traceback (most recent call last):
  File stdin, line 1, in module
NameError: name 'z' is not defined

The clause at the end x+y==z should be preceded by 'if' rather than a
comma. Commas separate function arguments and elements of collections
in displays. Expressions separated by commas without brackets are
interpreted as tuples:

 a = 1, 0
 a
(1, 0)

So your outermost loop is over a tuple (range(y, 10), x+y==z):
 [x for x in 1, 2]
[1, 2]
 [x for x in 'a', 'w', 'b']
['a', 'w', 'b']
 [x for x in range(3), False]
[[0, 1, 2], False]

Which explains the output you get:

 somelist
 [(1, 1, [1, 2, 3, 4, 5, 6, 7, 8, 9]), (1, 1, False), (1, 2, [2, 3, 4, 5, 6, 
 7, 8, 9]), (1, 2, False), (1, 3, [3, 4, 5, 6, 7, 8, 9]), (1, 3, False), (1, 
 4, [4, 5, 6, 7, 8, 9]), (1, 4, False), (1, 5, [5, 6, 7, 8, 9]), (1, 5, 
 False), (1, 6, [6, 7, 8, 9]), (1, 6, False), (1, 7, [7, 8, 9]), (1, 7, 
 False), (1, 8, [8, 9]), (1, 8, False), (1, 9, [9]), (1, 9, False), (2, 2, [2, 
 3, 4, 5, 6, 7, 8, 9]), (2, 2, False), (2, 3, [3, 4, 5, 6, 7, 8, 9]), (2, 3, 
 False), (2, 4, [4, 5, 6, 7, 8, 9]), (2, 4, False), (2, 5, [5, 6, 7, 8, 9]), 
 (2, 5, False), (2, 6, [6, 7, 8, 9]), (2, 6, False), (2, 7, [7, 8, 9]), (2, 7, 
 False), (2, 8, [8, 9]), (2, 8, False), (2, 9, [9]), (2, 9, False), (3, 3, [3, 
 4, 5, 6, 7, 8, 9]), (3, 3, False), (3, 4, [4, 5, 6, 7, 8, 9]), (3, 4, False), 
 (3, 5, [5, 6, 7, 8, 9]), (3, 5, False), (3, 6, [6, 7, 8, 9]), (3, 6, False), 
 (3, 7, [7, 8, 9]), (3, 7, False), (3, 8, [8, 9]), (3, 8, False), (3, 9, [9]), 
 (3, 9, False), (4, 4, [4, 5, 6, 7, 8, 9]), (4, 4, False), (4, 5, [5, 6, 7, 8, 
 9]), 
 (4
  , 5, False), (4, 6, [6, 7, 8, 9]), (4, 6, False), (4, 7, [7, 8, 9]), (4, 7, 
 False), (4, 8, [8, 9]), (4, 8, False), (4, 9, [9]), (4, 9, False), (5, 5, [5, 
 6, 7, 8, 9]), (5, 5, False), (5, 6, [6, 7, 8, 9]), (5, 6, False), (5, 7, [7, 
 8, 9]), (5, 7, False), (5, 8, [8, 9]), (5, 8, False), (5, 9, [9]), (5, 9, 
 False), (6, 6, [6, 7, 8, 9]), (6, 6, False), (6, 7, [7, 8, 9]), (6, 7, 
 False), (6, 8, [8, 9]), (6, 8, False), (6, 9, [9]), (6, 9, False), (7, 7, [7, 
 8, 9]), (7, 7, False), (7, 8, [8, 9]), (7, 8, False), (7, 9, [9]), (7, 9, 
 False), (8, 8, [8, 9]), (8, 8, False), (8, 9, [9]), (8, 9, False), (9, 9, 
 [9]), (9, 9, False)]

If you put the 'if' keyword in place of the comma it should work:
 [x for x in 'a', 'w', 'b' if x != 'b']
['a', 'w']


Oscar
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Strange behaviour of list comprehension

2013-02-13 Thread Peter Otten
Mahadevan, Anand wrote:

 I'm playing around with list comprehension and in IDLE typed this in.  I
 actually wanted it to return all tuples satisfying the condition where z
 is the sum of x and y. I kind of got mixed up with the syntax, hence I put
 a comma in there instead of an if.  I'd like some assistance
 understanding what it's doing... Thanks!
 
 somelist = [(x,y,z) for x in range(1,10) for y in range(x,10) for z in
 range(y,10), x+y==z] somelist

If you're puzzled about a list comprehension, try translating it into for 
loops:

somelist = []
for x in range(1, 10):
for y in range(x, 10):
for z in range(y, 10), x+y==z:
somelist.append((x, y, z))

In the first iteration you get x=1, y=1, so let's see what the inner loop 
gives:

 x = y = 1
 for z in range(y, 10), x+y==z:
... print z
... 
Traceback (most recent call last):
  File stdin, line 1, in module
NameError: name 'z' is not defined

So if you don't get a NameError you have defined z before entering the inner 
loop. Let's fix that:

 z = 42
 for z in range(y, 10), x+y==z:
... print z
... 
[1, 2, 3, 4, 5, 6, 7, 8, 9]
False

It should be obvious now that Python interprets

range(y, 10), x+y==z

as a tuple and iterates over that. range(1, 10) is a list in Python 2, so 
you are getting that first, then follows a boolean expression x+y == z which 
gives either True or False.

___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Strange behaviour of list comprehension

2013-02-13 Thread Hugo Arts
On Wed, Feb 13, 2013 at 2:45 PM, Mahadevan, Anand maha...@labcorp.comwrote:

 I'm playing around with list comprehension and in IDLE typed this in.  I
 actually wanted it to return all tuples satisfying the condition where z is
 the sum of x and y. I kind of got mixed up with the syntax, hence I put a
 comma in there instead of an if.  I'd like some assistance understanding
 what it's doing...
 Thanks!

  somelist = [(x,y,z) for x in range(1,10) for y in range(x,10) for z in
 range(y,10), x+y==z]
  somelist
 [(1, 1, [1, 2, 3, 4, 5, 6, 7, 8, 9]), (1, 1, False), (1, 2, [2, 3, 4, 5,
 6, 7, 8, 9]), (1, 2, False), (1, 3, [3, 4, 5, 6, 7, 8, 9]), (1, 3, False),
 (1, 4, [4, 5, 6, 7, 8, 9]), (1, 4, False), (1, 5, [5, 6, 7, 8, 9]), (1, 5,
 False), (1, 6, [6, 7, 8, 9]), (1, 6, False), (1, 7, [7, 8, 9]), (1, 7,
 False), (1, 8, [8, 9]), (1, 8, False), (1, 9, [9]), (1, 9, False), (2, 2,
 [2, 3, 4, 5, 6, 7, 8, 9]), (2, 2, False), (2, 3, [3, 4, 5, 6, 7, 8, 9]),
 (2, 3, False), (2, 4, [4, 5, 6, 7, 8, 9]), (2, 4, False), (2, 5, [5, 6, 7,
 8, 9]), (2, 5, False), (2, 6, [6, 7, 8, 9]), (2, 6, False), (2, 7, [7, 8,
 9]), (2, 7, False), (2, 8, [8, 9]), (2, 8, False), (2, 9, [9]), (2, 9,
 False), (3, 3, [3, 4, 5, 6, 7, 8, 9]), (3, 3, False), (3, 4, [4, 5, 6, 7,
 8, 9]), (3, 4, False), (3, 5, [5, 6, 7, 8, 9]), (3, 5, False), (3, 6, [6,
 7, 8, 9]), (3, 6, False), (3, 7, [7, 8, 9]), (3, 7, False), (3, 8, [8, 9]),
 (3, 8, False), (3, 9, [9]), (3, 9, False), (4, 4, [4, 5, 6, 7, 8, 9]), (4,
 4, False), (4, 5, [5, 6, 7, 8, 9]), (4
  , 5, False), (4, 6, [6, 7, 8, 9]), (4, 6, False), (4, 7, [7, 8, 9]), (4,
 7, False), (4, 8, [8, 9]), (4, 8, False), (4, 9, [9]), (4, 9, False), (5,
 5, [5, 6, 7, 8, 9]), (5, 5, False), (5, 6, [6, 7, 8, 9]), (5, 6, False),
 (5, 7, [7, 8, 9]), (5, 7, False), (5, 8, [8, 9]), (5, 8, False), (5, 9,
 [9]), (5, 9, False), (6, 6, [6, 7, 8, 9]), (6, 6, False), (6, 7, [7, 8,
 9]), (6, 7, False), (6, 8, [8, 9]), (6, 8, False), (6, 9, [9]), (6, 9,
 False), (7, 7, [7, 8, 9]), (7, 7, False), (7, 8, [8, 9]), (7, 8, False),
 (7, 9, [9]), (7, 9, False), (8, 8, [8, 9]), (8, 8, False), (8, 9, [9]), (8,
 9, False), (9, 9, [9]), (9, 9, False)]


This list comprehension is basically interpreted like so:

 [(x,y,z) for x in range(1,10) for y in range(x,10) for z in (range(y,10),
x+y==z)]

To be more precise, the comma at the end is part of a tuple (you can omit
parentheses of a tuple in many cases). This makes the final for loop
iterate over the tuple (range(y, 10), x + y == z). You'll notice that this
only works if the variable 'z' is already defined, since the tuple isn't
constructed in the for loop. In other words, if we just run the code in a
clean interpreter we'll get a NameError:

Python 2.7.3 (default, Apr 10 2012, 23:31:26) [MSC v.1500 32 bit (Intel)]
on win32
Type copyright, credits or license() for more information.
 [(x,y,z) for x in range(1,10) for y in range(x,10) for z in
range(y,10), x+y==z]

Traceback (most recent call last):
  File pyshell#0, line 1, in module
[(x,y,z) for x in range(1,10) for y in range(x,10) for z in
range(y,10), x+y==z]
NameError: name 'z' is not defined

What happened in your case is probably you were running different
variations of the list comprehension in the same interpreter session. Since
the iterating variable in a for loop still exists after the for loop exits,
we won't encounter this error if we run a slightly different list
comprehension first:

Python 2.7.3 (default, Apr 10 2012, 23:31:26) [MSC v.1500 32 bit (Intel)]
on win32
Type copyright, credits or license() for more information.
 [(x,y,z) for x in range(1,10) for y in range(x,10) for z in range(y,10)
if x+y==z]
[(1, 1, 2), (1, 2, 3), (1, 3, 4), (1, 4, 5), (1, 5, 6), (1, 6, 7), (1, 7,
8), (1, 8, 9), (2, 2, 4), (2, 3, 5), (2, 4, 6), (2, 5, 7), (2, 6, 8), (2,
7, 9), (3, 3, 6), (3, 4, 7), (3, 5, 8), (3, 6, 9), (4, 4, 8), (4, 5, 9)]
 z
9


As you can see, z exists after we run a for loop with z in it. Its value is
still at the value it had during the last iteration. The same applies to x
and y. Looking at your output, you had values of x, y and z in your
interpreter session such that x + y == z evaluated to False. So the third
value in your tuples is cycling between range(y, 10) and False.

HTH,
Hugo
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Strange behaviour of list comprehension

2013-02-13 Thread Mark Lawrence

On 13/02/2013 14:17, Hugo Arts wrote:



To be more precise, the comma at the end is part of a tuple (you can
omit parentheses of a tuple in many cases).


Parantheses are not part of a tuple except in special cases, see 
http://docs.python.org/2/tutorial/datastructures.html#tuples-and-sequences


--
Cheers.

Mark Lawrence

___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Strange behaviour of list comprehension

2013-02-13 Thread eryksun
On Wed, Feb 13, 2013 at 9:17 AM, Hugo Arts hugo.yo...@gmail.com wrote:
 To be more precise, the comma at the end is part of a tuple (you can omit
 parentheses of a tuple in many cases). This makes the final for loop iterate
 over the tuple (range(y, 10), x + y == z). You'll notice that this only
 works if the variable 'z' is already defined, since the tuple isn't
 constructed in the for loop.

In 3.x the parser requires the parentheses in a list comprehension,
but not in a for loop. And the list comprehension is compiled as a
function, so you get an UnboundLocalError when trying to evaluate
x+y==z.

Just for fun, here's an example that makes a function from the code of
a list comprehension in 3.x. The function takes the first iterator in
the comprehension as an argument:

 f = lambda: [(x,y) for x in 'ab' for y in 'cd']
 lcomp = type(f)(f.__code__.co_consts[1], globals())

 lcomp(iter('12'))
[('1', 'c'), ('1', 'd'), ('2', 'c'), ('2', 'd')]

Never do this. The code assumes the argument is an iterator, so it's
easy to trigger a segfault:

 lcomp('12')
Segmentation fault
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Strange behaviour of list comprehension

2013-02-13 Thread Hugo Arts
On Wed, Feb 13, 2013 at 10:07 PM, Mahadevan, Anand maha...@labcorp.comwrote:

  Thanks for the good explanation, Hugo.  Not sure of the protocol for
 replying in this forum, when I clicked on reply it filled your id in.


Glad I could be of help :) For future reference, it's generally considered
politest to send all replies over the tutor mailing list as well so we can
all see them, especially if further discussion is possible. Either click
Reply All or make sure you have tutor@python.org in your CC list.

Hugo
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor