How to print a generator expression?

185,472

Solution 1

Quick answer:

Doing list() around a generator expression is (almost) exactly equivalent to having [] brackets around it. So yeah, you can do

>>> list((x for x in string.letters if x in (y for y in "BigMan on campus")))

But you can just as well do

>>> [x for x in string.letters if x in (y for y in "BigMan on campus")]

Yes, that will turn the generator expression into a list comprehension. It's the same thing and calling list() on it. So the way to make a generator expression into a list is to put brackets around it.

Detailed explanation:

A generator expression is a "naked" for expression. Like so:

x*x for x in range(10)

Now, you can't stick that on a line by itself, you'll get a syntax error. But you can put parenthesis around it.

>>> (x*x for x in range(10))
<generator object <genexpr> at 0xb7485464>

This is sometimes called a generator comprehension, although I think the official name still is generator expression, there isn't really any difference, the parenthesis are only there to make the syntax valid. You do not need them if you are passing it in as the only parameter to a function for example:

>>> sorted(x*x for x in range(10))
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

Basically all the other comprehensions available in Python 3 and Python 2.7 is just syntactic sugar around a generator expression. Set comprehensions:

>>> {x*x for x in range(10)}
{0, 1, 4, 81, 64, 9, 16, 49, 25, 36}

>>> set(x*x for x in range(10))
{0, 1, 4, 81, 64, 9, 16, 49, 25, 36}

Dict comprehensions:

>>> dict((x, x*x) for x in range(10))
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81}

>>> {x: x*x for x in range(10)}
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81}

And list comprehensions under Python 3:

>>> list(x*x for x in range(10))
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

>>> [x*x for x in range(10)]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

Under Python 2, list comprehensions is not just syntactic sugar. But the only difference is that x will under Python 2 leak into the namespace.

>>> x
9

While under Python 3 you'll get

>>> x
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined

This means that the best way to get a nice printout of the content of your generator expression in Python is to make a list comprehension out of it! However, this will obviously not work if you already have a generator object. Doing that will just make a list of one generator:

>>> foo = (x*x for x in range(10))
>>> [foo]
[<generator object <genexpr> at 0xb7559504>]

In that case you will need to call list():

>>> list(foo)
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

Although this works, but is kinda stupid:

>>> [x for x in foo]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

Solution 2

Unlike a list or a dictionary, a generator can be infinite. Doing this wouldn't work:

def gen():
    x = 0
    while True:
        yield x
        x += 1
g1 = gen()
list(g1)   # never ends

Also, reading a generator changes it, so there's not a perfect way to view it. To see a sample of the generator's output, you could do

g1 = gen()
[g1.next() for i in range(10)]

Solution 3

Or you can always map over an iterator, without the need to build an intermediate list:

>>> _ = map(sys.stdout.write, (x for x in string.letters if x in (y for y in "BigMan on campus")))
acgimnopsuBM

Solution 4

You can just wrap the expression in a call to list:

>>> list(x for x in string.letters if x in (y for y in "BigMan on campus"))
['a', 'c', 'g', 'i', 'm', 'n', 'o', 'p', 's', 'u', 'B', 'M']

Solution 5

>>> list(x for x in string.letters if x in (y for y in "BigMan on campus"))
['a', 'c', 'g', 'i', 'm', 'n', 'o', 'p', 's', 'u', 'B', 'M']
Share:
185,472
the wolf
Author by

the wolf

Updated on July 08, 2022

Comments

  • the wolf
    the wolf almost 2 years

    In the Python shell, if I enter a list comprehension such as:

    >>> [x for x in string.letters if x in [y for y in "BigMan on campus"]]
    

    I get a nicely printed result:

    ['a', 'c', 'g', 'i', 'm', 'n', 'o', 'p', 's', 'u', 'B', 'M']
    

    Same for a dictionary comprehension:

    >>> {x:x*2 for x in range(1,10)}
    {1: 2, 2: 4, 3: 6, 4: 8, 5: 10, 6: 12, 7: 14, 8: 16, 9: 18}
    

    If I enter a generator expression, I get not such a friendly response:

    >>> (x for x in string.letters if x in (y for y in "BigMan on campus"))
    <generator object <genexpr> at 0x1004a0be0>
    

    I know I can do this:

    >>> for i in _: print i,
    a c g i m n o p s u B M
    

    Other than that (or writing a helper function) can I easily evaluate and print that generator object in the interactive shell?

    • Andreas Jung
      Andreas Jung about 13 years
      What is the real problem here? What are you missing?
    • the wolf
      the wolf about 13 years
      @pynator: The "real problem" is just that I want to be able to print the content of generator object as I interactively build a comprehension at the interactive prompt. Calling list(_) does that. What I have done is used list comprehensions then turn those into genexp in larger code. These can fail at run time in ways that list comprehensions do not.
    • Kos
      Kos almost 11 years
      The short answer is that a generator expression cannot be printed because its values don't exist; they're generated on demand. What you can do (assuming the generator stops sometime) is get all the values out of it, like with list(), and then print them.
    • kendfss
      kendfss over 3 years
      Another way to do it is x = (i for i in range(1)); print(*x)
  • ncoghlan
    ncoghlan about 13 years
    The official term remains "generator expression" because the word "comprehension" implies iteration, which is one thing a genexp doesn't do, as this question and answer illustrate nicely :)
  • Milan Velebit
    Milan Velebit over 6 years
    Voted up because of the statement that a generator can be infinite, therefore causing a loop or a total halt (depending on your specs (lol)).
  • Milan Velebit
    Milan Velebit over 6 years
    In case the generator is infinite, it'll cause a loop.
  • AJNeufeld
    AJNeufeld almost 6 years
    list( generator-expression ) isn't printing the generator expression; it is generating a list (and then printing it in an interactive shell). Instead of generating a list, in Python 3, you could splat the generator expression into a print statement. Ie) print(*(generator-expression)). This prints the elements without commas and without brackets at the beginning and end.
  • Marek R
    Marek R about 5 years
    this is the only answer which actually prints contents of generator without creating huge object.
  • Deepank Verma
    Deepank Verma over 3 years
    Use [next(g1) for i in range(10)] in Python 3.
  • mfit
    mfit about 2 years
    Why do you need the * operator ( it would print the list without it as well)