Take the 2-minute tour ×

I see this kind of thing sometimes:

(k for k in (j for j in (i for i in xrange(10))))

Now this really bends my brain, and I would rather it wasn't presented in this way.

Are there any use-cases, or examples of having used these nested expressions where it was more elegant and more readable than if it had been a nested loop?

Edit: Thanks for the examples of ways to simplify this. It's not actually what I asked for, I was wondering if there were any times when it was elegant.

share|improve this question
"Sometimes"? Really? What are you reading? –  S.Lott Mar 15 '09 at 23:35
Code snippets, open-source projects. That would get code-reviewed out of anything I had ever managed. –  Ali Afshar Mar 15 '09 at 23:51
Where have you seen such a thing? Can you provide a specific URL? –  S.Lott Mar 16 '09 at 0:01
add comment

6 Answers

up vote 10 down vote accepted

Check PEP 202 which was where list comprehensions syntax was introduced to the language.

For understanding your example, there is a simple rule from Guido himself:

  • The form [... for x... for y...] nests, with the last index varying fastest, just like nested for loops.

Also from PEP 202, which serves to answer your question:

    List comprehensions provide a more concise way to create lists in
    situations where map() and filter() and/or nested loops would
    currently be used.

If you had a situation like that, you could find it to be more elegant. IMHO, though, multiple nested list comprehensions may be less clear in your code than nested for loops, since for loops are easily parsed visually.

share|improve this answer
add comment

If you're worried about too much complexity on one line, you could split it:

(k for k in 
    (j for j in 
        (i for i in xrange(10))))

I've always found line continuations to look a little weird in Python, but this does make it easier to see what each one is looping over. Since an extra assignment/lookup is not going to make or break anything, you could also write it like this:

gen1 = (i for i in xrange(10))
gen2 = (j for j in gen1)
gen3 = (k for k in gen2)

In practice, I don't think I've ever nested a comprehension more than 2-deep, and at that point it was still pretty easy to understand.

share|improve this answer
I removed the escapes. –  Soviut Mar 15 '09 at 22:51
add comment

Since they are generator expressions, you can bind each to it's own name to make it more readable without any change in performance. Changing it to a nested loop would likely be detrimental to performance.

irange = (i for i in xrange(10))
jrange = (j for j in irange)
krange = (k for k in jrange)

It really doesn't matter which you choose, I think the multi-line example is more readable, in general.

share|improve this answer
add comment

In the case of your example, I would probably write it as:

foos = (i for i in xrange(10))
bars = (j for j in foos)
bazs = (k for k in bars)

Given more descriptive names, I think this would probably be quite clear, and I can't imagine there being any measurable performance difference.

Perhaps you're thinking more of expressions like:

(x for x in xs for xs in ys for ys in lst)

-- actually, that's not even valid. You have to put things in the other order:

(x for ys in lst for xs in ys for x in xs)

I might write that as a quick way of flattening a list, but in general I think you're write: the time you save by typing less is usually balanced by the extra time you spend getting the generator expression right.

share|improve this answer
add comment

The expression:


is equivalent to:

(i for i in xrange(10))

that is almost the same:


The last variant is more elegant than the first one.

share|improve this answer
add comment

I find it can be useful and elegant in situations like these where you have code like this:

output = []
for item in list:
    if item >= 1:
        new = item += 1

You can make it a one-liner like this:

output = [item += 1 for item in list if item >= 1]
share|improve this answer
add comment

Your Answer


