2009-12-15 10 views
6

Considere el siguiente código:estilo de estilo Lisp `let` sintaxis en Python lista por comprensión

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

Lo que este código no es imprimir los elementos de la diccionario versions en orden ascendente de su keys, pero desde el value es otra lista ordenada, solo se imprime el resumen de su primer elemento (el 'máximo').

Desde que estoy familiarizado con let de Lisp, Reescribí lo anterior como:

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

¿Cree que esto viola being Pythonic? ¿Se puede mejorar?

Nota: Para los curiosos, colprint se define here.

+3

Heh. Intentar ser lispy es _todos_ antiponético. Python intenta no listarse tan fuerte como puede. – Svante

+2

Es difícil hablar Parsel con un ceceo; [. – Tordek

+0

python no intenta ser como lisp. GvR mismo ha dicho que PYthon y Lisp son muy similares, y que las diferencias son más superficiales. Yo mismo vengo de un esquema, pero he estado usando Python casi exclusivamente durante tres años, y me gusta la segunda vía más que la primera. – Broseph

Respuesta

7

¿Por qué no explotar las tuplas?

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

o, incluso

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

Además, es posible tener en cuenta (en mi primer ejemplo) la eliminación de los [] s, porque de esa manera se obtiene un generador en lugar de una lista (que puede ser o no ser útil, ya que supongo que esto imprimirá toda la matriz, por lo que no guardará ninguna evaluación).

+0

Estaba a punto de sugerir el mismo –

+0

Se ve mejor; excepto que usaría 'items()' en lugar de 'iteritems()' ya que está en desuso en Py3k (y 'colprint' acepta una lista aplanada) –

4

Así que está usando "para x en [y]" como sustituto de "let x y".

Intentar emular la sintaxis del lenguaje en otro idioma nunca es una buena idea. Creo que la versión original es mucho más clara.

0

Puede mover la clasificación hasta el final para evitar algunas listas intermedias.

Esto se ve un poco más agradable que supongo:

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

python3 puede hacer aún mejor:

colprint(sorted(
     (name, first_version.summary or '') 
     for (name,(first_version,*_)) in versions.items()) 
    )) 
+1

? ¿Qué lenguaje es este? Obtengo un error de sintaxis en Python. –

+2

El 2do es Python ** 3 ** –

5

No utilizaría el "complicado para la cláusula" (o "let-equivalente") en la mayoría de los casos, pero lo haría si fuera la forma natural de evitar la repetición, especialmente la repetición costosa. P.ej.

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

se ve mucho mejor para mí que llamar tres veces somefun -!) Por lo tanto, vale la pena tener en cuenta, aunque probablemente no vale la pena utilizar en los que no elimina la repetición.

1

Como dice Tordek, puede utilizar items() o iteritems() en este caso para evitar el problema:

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

Traslado de la clasificación fuera es un buen toque.

[Tenga en cuenta que el uso de items() cambió ligeramente el orden de clasificación - solía ser por nombre con vínculos resueltos por orden original (el género Python es estable), ahora es por nombre con vínculos resueltos por resumen.Como el orden original de un dict es aleatorio, el nuevo comportamiento es probablemente mejor.]

Pero para otros usos (como el ejemplo de Alex Martelli), un "let" -alike podría ser útil. También descubrí una vez el truco for var in [value], pero ahora me parece feo. Una alternativa más limpia podría ser un "pipeline" de comprensiones/generadores, usando el truco "decorar/Undecorate" para pasar el valor añadido en una tupla:

# 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)) 

O aplicado al ejemplo de Alex:

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

(en el que ni siquiera necesita los z valores originales, por lo que los valores intermedios no tienen que ser tuplas.)

Ver http://www.dabeaz.com/generators/ para ejemplos más poderosos de la técnica de "pipeline" ...

Cuestiones relacionadas