Considere las siguientes expresiones. Tenga en cuenta que algunas expresiones se repiten para presentar el "contexto".
(esta es una lista larga)
a, b = 1, 2 # simple sequence assignment
a, b = ['green', 'blue'] # list asqignment
a, b = 'XY' # string assignment
a, b = range(1,5,2) # any iterable will do
# nested sequence assignment
(a,b), c = "XY", "Z" # a = 'X', b = 'Y', c = 'Z'
(a,b), c = "XYZ" # ERROR -- too many values to unpack
(a,b), c = "XY" # ERROR -- need more than 1 value to unpack
(a,b), c, = [1,2],'this' # a = '1', b = '2', c = 'this'
(a,b), (c,) = [1,2],'this' # ERROR -- too many values to unpack
# extended sequence unpacking
a, *b = 1,2,3,4,5 # a = 1, b = [2,3,4,5]
*a, b = 1,2,3,4,5 # a = [1,2,3,4], b = 5
a, *b, c = 1,2,3,4,5 # a = 1, b = [2,3,4], c = 5
a, *b = 'X' # a = 'X', b = []
*a, b = 'X' # a = [], b = 'X'
a, *b, c = "XY" # a = 'X', b = [], c = 'Y'
a, *b, c = "X...Y" # a = 'X', b = ['.','.','.'], c = 'Y'
a, b, *c = 1,2,3 # a = 1, b = 2, c = [3]
a, b, c, *d = 1,2,3 # a = 1, b = 2, c = 3, d = []
a, *b, c, *d = 1,2,3,4,5 # ERROR -- two starred expressions in assignment
(a,b), c = [1,2],'this' # a = '1', b = '2', c = 'this'
(a,b), *c = [1,2],'this' # a = '1', b = '2', c = ['this']
(a,b), c, *d = [1,2],'this' # a = '1', b = '2', c = 'this', d = []
(a,b), *c, d = [1,2],'this' # a = '1', b = '2', c = [], d = 'this'
(a,b), (c, *d) = [1,2],'this' # a = '1', b = '2', c = 't', d = ['h', 'i', 's']
*a = 1 # ERROR -- target must be in a list or tuple
*a = (1,2) # ERROR -- target must be in a list or tuple
*a, = (1,2) # a = [1,2]
*a, = 1 # ERROR -- 'int' object is not iterable
*a, = [1] # a = [1]
*a = [1] # ERROR -- target must be in a list or tuple
*a, = (1,) # a = [1]
*a, = (1) # ERROR -- 'int' object is not iterable
*a, b = [1] # a = [], b = 1
*a, b = (1,) # a = [], b = 1
(a,b),c = 1,2,3 # ERROR -- too many values to unpack
(a,b), *c = 1,2,3 # ERROR - 'int' object is not iterable
(a,b), *c = 'XY', 2, 3 # a = 'X', b = 'Y', c = [2,3]
# extended sequence unpacking -- NESTED
(a,b),c = 1,2,3 # ERROR -- too many values to unpack
*(a,b), c = 1,2,3 # a = 1, b = 2, c = 3
*(a,b) = 1,2 # ERROR -- target must be in a list or tuple
*(a,b), = 1,2 # a = 1, b = 2
*(a,b) = 'XY' # ERROR -- target must be in a list or tuple
*(a,b), = 'XY' # a = 'X', b = 'Y'
*(a, b) = 'this' # ERROR -- target must be in a list or tuple
*(a, b), = 'this' # ERROR -- too many values to unpack
*(a, *b), = 'this' # a = 't', b = ['h', 'i', 's']
*(a, *b), c = 'this' # a = 't', b = ['h', 'i'], c = 's'
*(a,*b), = 1,2,3,3,4,5,6,7 # a = 1, b = [2, 3, 3, 4, 5, 6, 7]
*(a,*b), *c = 1,2,3,3,4,5,6,7 # ERROR -- two starred expressions in assignment
*(a,*b), (*c,) = 1,2,3,3,4,5,6,7 # ERROR -- 'int' object is not iterable
*(a,*b), c = 1,2,3,3,4,5,6,7 # a = 1, b = [2, 3, 3, 4, 5, 6], c = 7
*(a,*b), (*c,) = 1,2,3,4,5,'XY' # a = 1, b = [2, 3, 4, 5], c = ['X', 'Y']
*(a,*b), c, d = 1,2,3,3,4,5,6,7 # a = 1, b = [2, 3, 3, 4, 5], c = 6, d = 7
*(a,*b), (c, d) = 1,2,3,3,4,5,6,7 # ERROR -- 'int' object is not iterable
*(a,*b), (*c, d) = 1,2,3,3,4,5,6,7 # ERROR -- 'int' object is not iterable
*(a,*b), *(c, d) = 1,2,3,3,4,5,6,7 # ERROR -- two starred expressions in assignment
*(a,b), c = 'XY', 3 # ERROR -- need more than 1 value to unpack
*(*a,b), c = 'XY', 3 # a = [], b = 'XY', c = 3
(a,b), c = 'XY', 3 # a = 'X', b = 'Y', c = 3
*(a,b), c = 'XY', 3, 4 # a = 'XY', b = 3, c = 4
*(*a,b), c = 'XY', 3, 4 # a = ['XY'], b = 3, c = 4
(a,b), c = 'XY', 3, 4 # ERROR -- too many values to unpack
¿Cómo deducir correctamente el resultado de tales expresiones a mano?
python
python-3.x
iterable-unpacking
argument-unpacking
codificador de árbol
fuente
fuente
a, *b = 1, 2, 3
tipo de desembalaje. Pero esto es Py3k, ¿verdad?Respuestas:
Mis disculpas por la extensión de esta publicación, pero decidí optar por la integridad.
Una vez que conozca algunas reglas básicas, no es difícil generalizarlas. Haré todo lo posible para explicarlo con algunos ejemplos. Ya que está hablando de evaluar estos "a mano", sugeriré algunas reglas de sustitución simples. Básicamente, es posible que le resulte más fácil comprender una expresión si todos los iterables tienen el mismo formato.
Solo con el propósito de desempacar, las siguientes sustituciones son válidas en el lado derecho de
=
(es decir, para rvalues ):Si encuentra que un valor no se descomprime, deshará la sustitución. (Consulte a continuación para obtener más explicaciones).
Además, cuando veas comas "desnudas", finge que hay una tupla de nivel superior. Haga esto en ambos lados izquierdo y el lado derecho (es decir, para lvalues y rvalues ):
Con esas simples reglas en mente, aquí hay algunos ejemplos:
La aplicación de las reglas anteriores, convertimos
"XY"
a('X', 'Y')
, y cubrimos las comas desnudas en parens:La correspondencia visual aquí hace que sea bastante obvio cómo funciona la tarea.
Aquí tienes un ejemplo erróneo:
Siguiendo las reglas de sustitución anteriores, obtenemos lo siguiente:
Esto es claramente erróneo; las estructuras anidadas no coinciden. Ahora veamos cómo funciona para un ejemplo un poco más complejo:
Aplicando las reglas anteriores, obtenemos
Pero ahora está claro por la estructura que
'this'
no se descomprimirá, sino que se asignará directamente ac
. Entonces deshacemos la sustitución.Ahora veamos qué sucede cuando ajustamos
c
una tupla:Se convierte
Una vez más, el error es obvio.
c
ya no es una variable desnuda, sino una variable dentro de una secuencia, por lo que la secuencia correspondiente a la derecha se descomprime en(c,)
. Pero las secuencias tienen una longitud diferente, por lo que hay un error.Ahora para un desembalaje prolongado con el
*
operador. Esto es un poco más complejo, pero sigue siendo bastante sencillo. Una variable precedida por se*
convierte en una lista, que contiene los elementos de la secuencia correspondiente que no están asignados a los nombres de las variables. Comenzando con un ejemplo bastante simple:Esto se convierte en
La forma más sencilla de analizar esto es trabajar desde los extremos.
'X'
está asignadoa
y'Y'
está asignado ac
. Los valores restantes de la secuencia se colocan en una lista y se asignan ab
.Los valores L como
(*a, b)
y(a, *b)
son solo casos especiales de lo anterior. No puede tener dos*
operadores dentro de una secuencia lvalue porque sería ambiguo. ¿Dónde irían los valores en algo como esto(a, *b, *c, d)
, enb
oc
? Consideraré el caso anidado en un momento.Aquí el error se explica por sí mismo. El objetivo (
*a
) debe estar en una tupla.Esto funciona porque hay una coma desnuda. Aplicando las reglas ...
Dado que no hay otras variables que no sean
*a
,*a
absorbe todos los valores en la secuencia rvalue. ¿Qué pasa si reemplaza el(1, 2)
con un valor único?se convierte en
Una vez más, el error aquí se explica por sí mismo. No puede descomprimir algo que no es una secuencia y
*a
necesita algo para desempaquetar. Entonces lo ponemos en una secuenciaQue es equivalente a
Finalmente, este es un punto común de confusión:
(1)
es lo mismo que1
: necesita una coma para distinguir una tupla de una declaración aritmética.Ahora para anidar. En realidad, este ejemplo no estaba en su sección "NESTED"; tal vez no te diste cuenta de que estaba anidado?
Se convierte
Se asigna el primer valor en la tupla de nivel superior, y los valores restantes en la tupla de nivel superior (
2
y3
) se asignanc
, tal como deberíamos esperar.Ya he explicado anteriormente por qué la primera línea arroja un error. La segunda línea es tonta, pero aquí está la razón por la que funciona:
Como se explicó anteriormente, trabajamos desde los extremos.
3
se asigna ac
, y luego los valores restantes se asignan a la variable con el*
anterior, en este caso(a, b)
,. Entonces eso es equivalente a(a, b) = (1, 2)
, que funciona porque hay el número correcto de elementos. No puedo pensar en ninguna razón por la que esto aparezca en el código de trabajo. Similar,se convierte en
Trabajar desde los extremos,
's'
se asignac
y('t', 'h', 'i')
se asigna a(a, *b)
. Trabajando de nuevo desde los extremos,'t'
se asignaa
y('h', 'i')
se asigna a b como una lista. Este es otro ejemplo tonto que nunca debería aparecer en el código de trabajo.fuente
Encuentro el desempaquetado de tuplas de Python 2 bastante sencillo. Cada nombre de la izquierda se corresponde con una secuencia completa o con un solo elemento en una secuencia de la derecha. Si los nombres corresponden a elementos individuales de cualquier secuencia, entonces debe haber suficientes nombres para cubrir todos los elementos.
Sin embargo, el desembalaje prolongado puede resultar confuso porque es muy poderoso. La realidad es que nunca debería estar haciendo los últimos 10 o más ejemplos válidos que dio; si los datos están así de estructurados, deberían estar en una
dict
instancia de clase o, no en formularios no estructurados como listas.Claramente, se puede abusar de la nueva sintaxis. La respuesta a su pregunta es que no debería tener que leer expresiones como esa; son una mala práctica y dudo que se utilicen.
El hecho de que pueda escribir expresiones arbitrariamente complejas no significa que deba hacerlo. Podrías escribir código como
map(map, iterable_of_transformations, map(map, iterable_of_transformations, iterable_of_iterables_of_iterables))
pero no lo haces .fuente
Creo que su código puede ser engañoso, use otra forma para expresarlo.
Es como usar corchetes adicionales en expresiones para evitar preguntas sobre la precedencia de los operadores. Siempre es una buena inversión hacer que su código sea legible.
Prefiero usar el desempaquetado solo para tareas simples como intercambiar.
fuente