Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python: understanding (None for g in g if (yield from g) and False)

Tags:

python

James Powell, in his short description for an upcoming presentation, says he is the proud inventor of one of the gnarliest Python one-liners:

(None for g in g if (yield from g) and False)

I am trying to figure out this generator, and since I live with Python 2.7.x, I'm also tripping over the (yield from g) expression.

How do I read this, and what would be the python 2.7.x analog?


What a great discussion below! I want to check if I have this correct in the main.

>>> l = [10, 11, iter(xrange(5)), 12, 13]
>>> g = iter(l)
>>> flat_g = (None for g in g if (yield from g) and False)
>>> list(flat_g)
[10, 11, 0, 1, 2, 3, 4, 12, 13]

Is that about right?

like image 447
Cole Avatar asked Mar 07 '14 16:03

Cole


1 Answers

This expression seems to be a code-golf way of writing:

(a for b in g for a in b)

((Or maybe the motivation be taking advantage of generator delegations, but IMHO readability really suffers.))

For example:

#! /usr/bin/python3.3

g = ['abc', 'def', 'ghi']

a = (None for g in g if (yield from g) and False)
for x in a: print (x)

b = (a for b in g for a in b)
for x in b: print (x)

Prints twice the flattened list.

I think it becomes more legible if you use different variable names:

(None for sublist in g if (yield from sublist) and False)

Which is the same as

(42 for sublist in g if (yield from sublist) and False)

as due to the something and False the outer generator doesn't yield anything, while the inner generator yields all elements of all sublists (subgenerators, subiterables).

Maybe this clarifies a bit how it works:

('Sublist {}'.format(idx) for idx, sublist in enumerate(g) if (yield from sublist) or True)

Apparently the original generator can be simplified to this, omitting the last and False:

(None for sublist in g if (yield from sublist) )

Revision:

Thanks to Martijn Pieters fighting my stubbornness, I managed to see that (None for sublist in g if (yield from sublist) and False) and (None for sublist in g if (yield from sublist) ) are not equivalent. Here an example of a g which makes a difference:

def f():
    yield 1
    return 2

def g():
    yield f()

a = (None for sublist in g() if (yield from sublist) )
for x in a: print(x)
a = (None for sublist in g() if (yield from sublist) and False)
for x in a: print(x)

This prints:

1
None
1
like image 92
Hyperboreus Avatar answered Oct 01 '22 07:10

Hyperboreus