Explanation of this Python language feature? [x for x in x for x in x] (to flatten a nested list)

Rustom Mody rustompmody at gmail.com
Mon Mar 24 00:14:20 EDT 2014


On Monday, March 24, 2014 8:57:32 AM UTC+5:30, Chris Angelico wrote:
> On Mon, Mar 24, 2014 at 1:35 PM, Rhodri James  wrote:
> >> Would you not consider this to be declarative?
> >>    x = [1, 2, 3]
> > I'm not sure I would.  I look at that line of code and think of it as
> > "Create a list...", very much in an imperative manner.  Then again, compared
> > with C structs and typedefs and actual honest-to-God type declarations,
> > there's precious little in Python I would consider truly declarative.

> I'm in the declarative group here. Yes, it has to be implemented as
> creating a list and adding three elements to it, but conceptually, it
> means "Bind x to a new list with these elements". And as long as
> that's the end result, I don't care how it's done; the interpreter's
> most welcome to have a "template list" that it copies, or maybe a
> literal tuple that gets passed to the list() constructor, or
> whatever's most efficient.

> It gets a bit messier when there's stuff with side effects, though.
> This has to be a bit more imperative:

> x = [foo(y), bar(y), quux(y)]

> That means "Call foo, bar, and quux, in that order, each with y as an
> argument, and bind x to a new list with their return values". And if
> Python had a simple notation for calling a series of functions, that
> could be written something like this:

> funcs = [foo, bar, quux]
> x = funcs(y)

> which is looking more declarative again. It's now "Take this list of
> functions and call them all, and bind x to a list of their return
> values". (This could be done, with a callable subclass of list. Call
> it a sort of "implicit map" if you like.) Python doesn't have that
> syntax, but it does have this:

> x = [f(y) for f in funcs]

> and I'd say that's reasonably declarative; it should be read like the
> previous one: "Take this list of funcs, call each one, and bind x to a
> list of their return values". And I could imagine a
> parallel-processing version of a list comp that functions like
> multiprocessing.Pool.map() and doesn't promise order, which would
> *definitely* be declarative.

You have described nicely a slippery slope!

The list
[(1, 1), (1, 2), (1, 3), (1, 4), (2, 1), (2, 2), (2, 3), (2, 4), (3, 1), (3, 2), (3, 3), (3, 4)]

looks neater written (and *thought of* ) as
[(x,y) for x in range(1,4) for y in range(1,5)]

Neat! So I play around... Change it to
[(x,y) for x in range(1,10000) for y in range(1,10000)]
and I dont have an answer but a thrashing machine!! (*)

IOW everything we write/read as programmers has a declarative and an
imperative side.
Which one one wants to focus on requires good sense and taste.

(*) Example also shows inter alia how some things -- range -- have gone from
imperative to declarative from python 2 to 3.
Some people have made languages whose main focus is generalizing this
idea to more dimensions and restrictions:
http://www.irisa.fr/cosi/Rajopadhye/dag-talk.ps



More information about the Python-list mailing list