Como todos sabemos, hay una lista de comprensión, como
[i for i in [1, 2, 3, 4]]
y hay comprensión del diccionario, como
{i:j for i, j in {1: 'a', 2: 'b'}.items()}
pero
(i for i in (1, 2, 3))
terminará en un generador, no en una tuple
comprensión. ¿Porqué es eso?
Supongo que a tuple
es inmutable, pero esta no parece ser la respuesta.
{i:j for i,j in {1:'a', 2:'b'}}
debería ser{i:j for i,j in {1:'a', 2:'b'}.items()}
Respuestas:
Puedes usar una expresión generadora:
pero los paréntesis ya se tomaron para ... expresiones generadoras.
fuente
list(i for i in (1,2,3))
. Realmente creo que es simplemente porque no hay una sintaxis limpia (o al menos nadie ha pensado en una)list(i for i in (1, 2, 3))
es una expresión generadora que genera una lista,set(i for i in (1, 2, 3))
genera un conjunto. ¿Eso significa que la sintaxis de comprensión no es necesaria? Quizás no, pero es muy útil. Para los casos raros que necesita una tupla, la expresión del generador funcionará, es clara y no requiere la invención de otro paréntesis o paréntesis.[thing for thing in things]
construye una lista mucho más rápida quelist(thing for thing in things)
. Una comprensión de tuplas no sería inútil;tuple(thing for thing in things)
tiene problemas de latencia ytuple([thing for thing in things])
podría tener problemas de memoria.A list or set or dict comprehension is just syntactic sugar to use a generator expression
? Está causando confusión al ver a las personas como un medio equivalente para un fin. No es azúcar técnicamente sintáctico ya que los procesos son realmente diferentes, incluso si el producto final es el mismo.Raymond Hettinger (uno de los desarrolladores principales de Python) dijo lo siguiente sobre las tuplas en un tweet reciente :
Esto (para mí) respalda la idea de que si los elementos en una secuencia están lo suficientemente relacionados como para ser generados por un generador, bueno, entonces debería ser una lista. Aunque una tupla es iterable y parece simplemente una lista inmutable, es realmente el equivalente de Python de una estructura C:
se convierte en Python
fuente
operator.itemgetter
en ese caso.tuple(obj[item] for item in items)
directamente. En mi caso, estaba incrustando esto en una lista de comprensión para hacer una lista de registros de tuplas. Si necesito hacer esto repetidamente en todo el código, itemgetter se ve muy bien. ¿Tal vez el itemgetter sería más idiomático de cualquier manera?Desde Python 3.5 , también puede usar la
*
sintaxis de desempaquetado splat para desempaquetar una expresión de generador:fuente
tuple(list(x for x in range(10)))
( las rutas de código son idénticas , y ambaslist
crean un, con la única diferencia de que el paso final es crear untuple
desdelist
y desechar ellist
cuando unatuple
salida es requerido). Significa que en realidad no evitas un par de temporarios.*(x for x in range(10))
no funciona. ConsigoSyntaxError: can't use starred expression here
. Sin embargotuple(x for x in range(10))
funciona.Como se
macm
menciona en otro póster , la forma más rápida de crear una tupla a partir de un generador estuple([generator])
.Comparación de rendimiento
Lista de comprensión:
Tupla de la comprensión de la lista:
Tupla del generador:
Tupla de desembalaje:
Mi versión de python :
Por lo tanto, siempre debe crear una tupla a partir de una comprensión de la lista a menos que el rendimiento no sea un problema.
fuente
tuple
de listcomp requiere un uso de memoria máximo basado en el tamaño combinado de la finaltuple
ylist
.tuple
de un genexpr, aunque más lento, significa que solo paga por el finaltuple
, no temporallist
(el genexpr en sí ocupa una memoria aproximadamente fija). Por lo general, no tiene sentido, pero puede ser importante cuando los tamaños involucrados son enormes.La comprensión funciona haciendo un bucle o iterando sobre los elementos y asignándolos a un contenedor, una Tupla no puede recibir asignaciones.
Una vez que se crea una Tupla, no se puede agregar, extender o asignar. La única forma de modificar una Tupla es si uno de sus objetos puede asignarse a sí mismo (es un contenedor sin tupla). Porque la Tupla solo tiene una referencia a ese tipo de objeto.
Además, una tupla tiene su propio constructor
tuple()
que puede asignar a cualquier iterador. Lo que significa que para crear una tupla, podrías hacer:fuente
lst = [x for x in ...]; x.append()
?Mi mejor conjetura es que se quedaron sin paréntesis y no pensaron que sería lo suficientemente útil como para justificar la adición de una sintaxis "fea" ...
fuente
{*()}
, aunque feo, ¡funciona como un conjunto vacío literal!set()
:){*[]}
es estrictamente inferior a las otras opciones; la cadena vacía y vacíatuple
, siendo inmutables, son singletons, por lo que no se necesita temporal para construir el vacíoset
. Por el contrario, el vacíolist
no es un singleton, por lo que realmente tiene que construirlo, usarlo para construirloset
y luego destruirlo, perdiendo cualquier ventaja de rendimiento trivial que proporciona el operador mono mono.Las tuplas no se pueden agregar eficientemente como una lista.
Por lo tanto, una comprensión de tupla necesitaría usar una lista internamente y luego convertirla en una tupla.
Eso sería lo mismo que haces ahora: tupla ([comprensión])
fuente
Los paréntesis no crean una tupla. aka one = (two) no es una tupla. La única forma de hacerlo es uno = (dos,) o uno = tupla (dos). Entonces una solución es:
fuente
Creo que es simplemente por razones de claridad, no queremos saturar el lenguaje con demasiados símbolos diferentes. Además, una
tuple
comprensión nunca es necesaria , una lista solo se puede usar en cambio con diferencias de velocidad insignificantes, a diferencia de una comprensión dictada en lugar de una comprensión de lista.fuente
Podemos generar tuplas a partir de una lista de comprensión. El siguiente agrega dos números secuencialmente en una tupla y da una lista de los números 0-9.
fuente