Consider 开发者_如何学Pythonthe following code:
>>> colprint([
(name, versions[name][0].summary or '')
for name in sorted(versions.keys())
])
What this code does is to print the elements of the dictionary versions
in ascending order of its keys
, but since the value
is another sorted list, only the summary of its first element (the 'max') is printed.
Since I am familiar with let
from lisp, I rewrote the above as:
>>> colprint([
(name, package.summary or '')
for name in sorted(versions.keys())
for package in [versions[name][0]]
)]
Do you think this violates being Pythonic? Can it be improved?
Note: For the curious, colprint
is defined here.
Why not exploit 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()]))
Also, you may consider (in my first example) removing the []
s, because that way you get a generator instead of a list (which may or may not be useful, since I'm guessing this'll print the whole array, so you won't be saving any evaluations).
I wouldn't use the "tricky for clause" (or "let-equivalent") in most cases, but I would if it's the natural way to avoid repetition, especially costly repetition. E.g.
xs = [(y, y*1.2, y-3.4) for z in zs for y in [somefun(z)] ]
looks much better to me than calling somefun
three times!-) So, it's worth keeping in mind, even if probably not worth using where it does not remove repetition.
So you're using "for x in [y]" as a substitute for "let x y".
Trying to emulate language's syntax in another language is never a good idea. I think that the original version is much clearer.
As Tordek says, you can use items()
or iteritems()
in this case to avoid the issue:
colprint(sorted((name, packages[0].summary or '')
for (name, packages) in versions.items()))
Moving the sorting outside is a nice touch.
[Note that the use of items()
changed the sorting order slightly - it used to be by name with ties resolved by original order (Python sort is stable), now it's by name with ties resolved by summary. Since the original order of a dict is random, the new behaviour is probably better.]
But for other uses (such as Alex Martelli's example), a "let"-alike might still be useful.
I've also once discovered the for var in [value]
trick, but I now find it ugly.
A cleaner alternative might be a "pipeline" of comprehensions / generators, using the "decorate/undecorate" trick to pass the added value in a 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 the intermediate values don't have to be tuples.)
See http://www.dabeaz.com/generators/ for more powerful examples of the "pipeline" technique...
You can move the sorting to the end to avoid some intermediate lists.
This looks a bit nicer i guess:
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())
))
精彩评论