2

Playing around with iPython, I was surprised to discover that given a list f of objects each supporting some method x() (that, say, prints out "Hi!"), the expression:

(y.x() for y in f)

is not semantically equivalent to

[y.x() for y in f]

The first one (with the tuple as output) results in a generator expression that is not evaluated unless I iterate over it, whereas the one with the list actually causes the generation to happen immediately:

In [30]: (y.x() for y in f)
Out[30]: <generator object <genexpr> at 0x2d78d70>

but

In [31]: [y.x() for y in f]
Hi!
Hi!
Hi!
Hi!

This seems rather counter-intuitive.

Question: Why is the first expression not generating a tuple of the values obtained from the generator the way the list is being built?


Update: As I stare at this more, I realize that perhaps what's happening in the first case is that Python is just building a tuple containing a generator rather than evaluating the generator as it is in the second case.

So is it true that it is not possible to directly get a tuple as the result of generating a list comprehension? (I understand I can do tuple([y.x() for y in f])). I don't have a use case, this is purely for my understanding.

scorpiodawg
  • 5,612
  • 3
  • 42
  • 62
  • Why is what? You already found out down what it means, even if it's not what you initially expected. Are you asking why generator expressions exist? Or are you asking why this syntax doesn't instead generate tuples (analogous to a list comprehension)? Or something else? –  Oct 09 '13 at 21:08
  • Are you asking why it's counter-intuitive, or why genexs exist? – Ignacio Vazquez-Abrams Oct 09 '13 at 21:09
  • If it's counter-intuitive, that means you expected some other behavior. What were you expecting? – recursive Oct 09 '13 at 21:09
  • The tuple constructor is a comma, best way to think about it – YXD Oct 09 '13 at 21:12
  • Updated my question to reflect the confusion. – scorpiodawg Oct 09 '13 at 21:12
  • 3
    BTW, that you expected a tuple is probably rooted in a misconception that will also bite you in other contexts: The assumption that parens signify a tuple. They don't. It's commas which create tuples. –  Oct 09 '13 at 21:15
  • The parens around the expression are the syntax that was chosen to *identify* an generator expression and they have nothing to do with tuples. There might be newsgroup discussions on that syntax - [PEP 289](http://www.python.org/dev/peps/pep-0289/) doesn't mention the rational for that design choice but it might be worth reading. – wwii Oct 10 '13 at 13:20

2 Answers2

3

Some people treat tuples as read-only lists, and that works in some contexts. But that is not the semantic intention of tuples. Lists are intended to be used for variable length structures of homogeneous elements (elements with a shared type). Tuples are intended for fixed length structures in which each indexed position contains a certain type of element.

enumerate(lst) is an example of this. It returns a variable-length list of tuples. Each tuple has exactly two elements, the first of which is always an integer, and the second of which is from lst.

With that understanding, a tuple generator is a bit nonsensical. That is probably why.

Edit:

As for directly generating a tuple, you can do a little bit better than your example. This also works:

tuple(y.x() for y in f)

That passes a generator to the tuple() method, which constructs a tuple, but doesn't create an intermediate list.

To be clear, there is no tuple involved in (y.x() for y in f), but there is a tuple in t = 1, 2, 3. It's not the parens that make the tuple. It's the commas.

recursive
  • 83,943
  • 34
  • 151
  • 241
0

Question: Why is the first expression not generating a tuple of the values obtained from the generator the way the list is being built?

That is not what is designed to do.
See PEP-289
Tutorial is always a good place to start looking for answers.
Generator Expressions
Expression lists - describes the use of a comma for defining a tuple

So is it true that it is not possible to directly get a tuple as the result of generating a list comprehension?

No -not like a list comprehension, it is a generator. It is designed to yield individual elements for each iteration.

wwii
  • 23,232
  • 7
  • 37
  • 77