4

I've been trying to convert this generator function into a generator expression, but with no success. Is it possible to have the same output with a generator expression?

    def gen5(num):
         for i in range(num):             
             yield i *2
             yield i *10
             yield i *i

    g = gen5(4) 
    list(g)
    [0, 0, 0, 2, 10, 1, 4, 20, 4, 6, 30, 9]

I've tried the following, but get this (None, None, None) output.

    gen_exp2 = (((yield u*2), (yield u*10) ,(yield u*u)) for u in  range(4))

    list(gen_exp2)

    [0,
     0,
     0,
     (None, None, None),
     2,
     10,
     1,
    (None, None, None),
     4,
    20,
     4,
    (None, None, None),
    6,
    30,
    9,
   (None, None, None)]

I've also done this, but it gives 4 nested tuples instead of the list above.

       gen_exp3 = (((i*2), (i*10), (i*i)) for i in range(4))

       list(gen_exp3)

       [(0, 0, 0), (2, 10, 1), (4, 20, 4), (6, 30, 9)]

Also, how can I add a parameter to a generator expression? Many thanks in advance.

5
  • 1
    You don't need the yield statements in a generator expression, surrounding the loop with parentheses is enough. Commented Nov 19, 2017 at 17:32
  • That doesn't generate the same output like the generator function. It gives 4 tuples. Commented Nov 19, 2017 at 17:34
  • You will need another nested for loop to "unpack" your tuples. Commented Nov 19, 2017 at 17:35
  • (x for i in range(num) for x in (i*2, i*10, i*i)) works, but is confusing to read. itertools.chain.from_iterable((i*2, i*10, i*i) for i in range(num)) too Commented Nov 19, 2017 at 17:36
  • Awesome. Thanks Patrick. I thought for a moment that I couldn't convert a generator function into a gen expression. Commented Nov 19, 2017 at 17:38

2 Answers 2

3

You just need a double loop in the gen exp:

num = 4
g = (j for i in range(num) for j in (i*2, i*10, i*i))
print(*g)

output

0 0 0 2 10 1 4 20 4 6 30 9

As Moses says, using yield in a gen exp is not a good idea.


Here's a cute variation, using map

g = (j for i in range(num) for j in map(i.__mul__, (2, 10, i)))

However, some people might not like that use of i.__mul__.


You asked: "How can I add a parameter to a generator expression?". Well, you can't. You could create a lambda, as Moses shows, but really you're better off making a proper generator function. Lambdas are supposed to be anonymous functions, so creating a lambda and binding it to a name is a rather dubious practice. ;)

Sign up to request clarification or add additional context in comments.

4 Comments

@JonClements I suppose one could. It'd be interesting to know how it compares speed-wise to i.__mul__.
I'd be surprised if it wasn't slower because of additional function calls and lookups...
@JonClements Me too. OTOH, I guess partial could be using some tricky C magic to do its stuff. The CPython source for functools has a Python wrapper here. I'm not having any luck trying to find the C source. Ah, here we go
My assumption would be that partial is somewhat slower because the mul indirection, and because it does need to make a 2-tuple for the arguments. I didn't try it yet though
2

You don't need to use yield in a generator expression.

See yield in list comprehensions and generator expressions on why this could easily be considered a bug, although it isn't.

You can use a nested comprehension to achieve the same thing in a generator expression:

gen_exp2 = (x for u in range(4) for x in (u*2, u*10, u*u))

And you can parameterise this by putting the generator expression in a function:

gen_fun = lambda num: (x for u in range(num) for x in (u*2, u*10, u*u)) 

Might be better to keep your original approach though, as using yield in a function may be faster than using a nested comprehension within a generator expression which is already pretty slow without nesting.

2 Comments

Understood your answer. Can you please provide the explanation for that output shown in the question? Just curious to know :)
@stack_n_queue Did you read the linked answer? Pretty much explains how the interpreter treats a yield in a gen. exp. and what happens behind the scenes: stack etc.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.