Lisp style style `let` syntax in Python lists

Consider the following code:

>>> colprint([ (name, versions[name][0].summary or '') for name in sorted(versions.keys()) ]) 

What this code does is print the elements of the versions dictionary in ascending order of its keys , but since value is another sorted list, only a summary of its first element ('max').

Since I am familiar with let from lisp, I rewrote the above:

 >>> colprint([ (name, package.summary or '') for name in sorted(versions.keys()) for package in [versions[name][0]] )] 

Do you think this violates how Pythonic ? Is it possible to improve?

Note. For the curious <<26> is defined here .

+6
python lisp refactoring
source share
5 answers

Why not use tuples?

 colprint([(name, version[0].summary or '') for (name, version) in sorted(versions.iteritems())]) 

or even

 colprint(sorted([(name, version[0].summary or '') for (name, version) in versions.iteritems()])) 

In addition, you can consider (in my first example) deleting [] s, because this way you get a generator instead of a list (which may or may not be useful, since I assume this will print the entire array, so you won’t save any ratings).

+7
source share

In most cases, I would not use a “complex sentence” (or “let-equivalent”), but I would do it in a natural way to avoid repetition, especially costly repetition. For example.

 xs = [(y, y*1.2, y-3.4) for z in zs for y in [somefun(z)] ] 

looks a lot better than calling somefun three times!). Therefore, it is worth keeping in mind, even if it is probably not worth using, where it does not delete repetitions.

+5
source share

So, you use "for x in [y]" as a replacement for "let xy".

Trying to emulate language syntax in another language is never a good idea. I think the original version is much clearer.

+4
source share

As Tordek says, you can use items() or iteritems() in this case to avoid the problem:

 colprint(sorted((name, packages[0].summary or '') for (name, packages) in versions.items())) 

Moving sorting outside is a nice touch.

[Note that using items() slightly changed the sort order - it was used by name with first-order relationships (Python sorting is stable), now it is by name with relationships resolved by summary. Since the original dict order is random, the new behavior is probably better.]

But for other purposes (for example, the example of Alex Martelli) a "let" -alike may be useful. I also once discovered a trick for var in [value] , but now I find it ugly. A cleaner alternative could be a “pipeline” of concepts / generators using the “decorate / undecorate” trick to pass the added value to the tuple:

 # You could write this with keys() or items() - # I'm just trying to examplify the pipeline technique. names_packages = ((name, versions[name][0]) for name in versions.keys()) names_summaries = ((name, package.summary or '') for (name, package) in names_packages) colprint(sorted(names_summaries)) 

Or applied to Alex's example:

 ys = (somefun(z) for z in zs) xs = [(y, y*1.2, y-3.4) for y in ys] 

(in which you don't even need the original z values, so intermediate values ​​don't have to be tuples.)

See http://www.dabeaz.com/generators/ for more powerful examples of the pipeline technique ...

+1
source share

You can move the sort to the end to avoid some intermediate lists.

It looks a little nicer, I think:

 colprint(sorted( (name, version[0].summary or '') for (name,version) in versions.iteritems()) )) 

Python3 can do even better:

 colprint(sorted( (name, first_version.summary or '') for (name,(first_version,*_)) in versions.items()) )) 
0
source share

All Articles