python - try - ¿Por qué no se asigna un error a una lista vacía(por ejemplo,[]=“”)?
tipos de excepción en python (2)
En Python 3.4, estoy escribiendo
[] = ""
y funciona bien, no se genera ninguna excepción.
Aunque, por supuesto,
[]
no es igual a
""
después.
[] = ()
También funciona bien.
"" = []
plantea una excepción como se esperaba, sin embargo,
() = ""
Sin embargo, plantea una excepción como se esperaba. Entonces, ¿qué está pasando?
No estás comparando por la igualdad. Estás asignando
Python le permite asignar a múltiples objetivos:
foo, bar = 1, 2
asigna los dos valores a
foo
y
bar
, respectivamente.
Todo lo que necesita es una
secuencia
o
iterable
en el lado derecho, y una lista o tupla de nombres a la izquierda.
Cuando tu lo hagas:
[] = ""
asignó una secuencia vacía (las cadenas vacías siguen siendo secuencias) a una lista vacía de nombres.
Es esencialmente lo mismo que hacer:
[foo, bar, baz] = "abc"
donde terminas con
foo = "a"
,
bar = "b"
y
baz = "c"
, pero con menos caracteres.
Sin embargo, no puede asignar a una cadena, por lo que
""
en el lado izquierdo de una asignación nunca funciona y siempre es un error de sintaxis.
Consulte la documentación de las declaraciones de asignación :
Una instrucción de asignación evalúa la lista de expresiones (recuerde que esta puede ser una sola expresión o una lista separada por comas, esta última produciendo una tupla) y asigna el único objeto resultante a cada una de las listas de destino, de izquierda a derecha.
y
La asignación de un objeto a una lista de destino, opcionalmente entre paréntesis o corchetes , se define de forma recursiva de la siguiente manera.
El énfasis es mío .
¡Que Python no arroje un error de sintaxis para la lista vacía es realmente un error!
La gramática oficialmente documentada no permite una lista de objetivos vacía, y para el vacío
()
se obtiene un error.
Ver
error 23275
;
se considera un error inofensivo:
El punto de partida es reconocer que esto ha existido durante mucho tiempo y es inofensivo.
Consulte también ¿Por qué es válido asignar a una lista vacía pero no a una tupla vacía?
Sigue las reglas de la sección Declaraciones de asignación de la documentación,
assignment_stmt ::= (target_list "=")+ (expression_list | yield_expression)
Si la
target list
es una lista de objetivos separados por comas: el objeto debe ser iterable con el mismo número de elementos que hay objetivos en la lista de objetivos, y los elementos se asignan, de izquierda a derecha, a los objetivos correspondientes.El objeto debe ser una secuencia con el mismo número de elementos que hay objetivos en la lista de objetivos, y los elementos se asignan, de izquierda a derecha, a los objetivos correspondientes.
Entonces, cuando dices
[] = ""
""
es iterable (cualquier cadena de Python válida es iterable) y se está desempaquetando sobre los elementos de la lista.
Por ejemplo,
>>> [a, b, c] = "123"
>>> a, b, c
(''1'', ''2'', ''3'')
Como tiene una cadena vacía y una lista vacía, no hay nada que desempaquetar. Entonces, no hay error.
Pero intenta esto
>>> [] = "1"
Traceback (most recent call last):
File "<input>", line 1, in <module>
ValueError: too many values to unpack (expected 0)
>>> [a] = ""
Traceback (most recent call last):
File "<input>", line 1, in <module>
ValueError: need more than 0 values to unpack
En el caso
[] = "1"
, está intentando descomprimir la cadena
"1"
sobre una lista vacía de variables.
Por lo tanto, se queja con "demasiados valores para descomprimir (esperado 0)".
Del mismo modo, en el caso
[a] = ""
, tiene una cadena vacía, por lo que no hay nada que desempaquetar realmente, pero la está desempacando sobre una variable, lo cual, nuevamente, no es posible.
Es por eso que se queja "necesita más de 0 valores para descomprimir".
Aparte de eso, como notaron,
>>> [] = ()
tampoco arroja ningún error, porque
()
es una tupla vacía.
>>> ()
()
>>> type(())
<class ''tuple''>
y cuando se desempaqueta sobre una lista vacía, no hay nada que desempaquetar. Entonces no hay error.
Pero cuando lo haces
>>> "" = []
File "<input>", line 1
SyntaxError: can''t assign to literal
>>> "" = ()
File "<input>", line 1
SyntaxError: can''t assign to literal
como dice el mensaje de error, está intentando asignar un literal de cadena. Lo cual no es posible. Por eso está recibiendo los errores. Es como decir
>>> 1 = "one"
File "<input>", line 1
SyntaxError: can''t assign to literal
Internos
Internamente, esta operación de asignación se traducirá al código de operación
UNPACK_SEQUENCE
,
>>> dis(compile(''[] = ""'', "string", "exec"))
1 0 LOAD_CONST 0 ('''')
3 UNPACK_SEQUENCE 0
6 LOAD_CONST 1 (None)
Aquí, dado que la cadena está vacía,
UNPACK_SEQUENCE
0
veces.
Pero cuando tienes algo como esto
>>> dis(compile(''[a, b, c] = "123"'', "string", "exec"))
1 0 LOAD_CONST 0 (''123'')
3 UNPACK_SEQUENCE 3
6 STORE_NAME 0 (a)
9 STORE_NAME 1 (b)
12 STORE_NAME 2 (c)
15 LOAD_CONST 1 (None)
18 RETURN_VALUE
la secuencia
123
se desempaqueta en la pila, de derecha a izquierda.
Entonces, la parte superior de la pila sería
1
y la siguiente sería
2
y la última sería
3
.
Luego asigna desde la parte superior de la pila a las variables de la expresión del lado izquierdo una por una.
Por cierto, en Python, así es como puedes hacer múltiples tareas en la misma expresión. Por ejemplo,
a, b, c, d, e, f = u, v, w, x, y, z
esto funciona porque los valores de la mano derecha se usan para construir una tupla y luego se desempaquetarán sobre los valores del lado izquierdo.
>>> dis(compile(''a, b, c, d, e, f = u, v, w, x, y, z'', "string", "exec"))
1 0 LOAD_NAME 0 (u)
3 LOAD_NAME 1 (v)
6 LOAD_NAME 2 (w)
9 LOAD_NAME 3 (x)
12 LOAD_NAME 4 (y)
15 LOAD_NAME 5 (z)
18 BUILD_TUPLE 6
21 UNPACK_SEQUENCE 6
24 STORE_NAME 6 (a)
27 STORE_NAME 7 (b)
30 STORE_NAME 8 (c)
33 STORE_NAME 9 (d)
36 STORE_NAME 10 (e)
39 STORE_NAME 11 (f)
42 LOAD_CONST 0 (None)
45 RETURN_VALUE
pero la técnica clásica de intercambio
a, b = b, a
utiliza la rotación de elementos en la parte superior de la pila.
Si solo tiene dos o tres elementos, se tratan con
ROT_TWO
especiales
ROT_TWO
y
ROT_THREE
lugar de construir la tupla y desempaquetarla.
>>> dis(compile(''a, b = b, a'', "string", "exec"))
1 0 LOAD_NAME 0 (b)
3 LOAD_NAME 1 (a)
6 ROT_TWO
7 STORE_NAME 1 (a)
10 STORE_NAME 0 (b)
13 LOAD_CONST 0 (None)
16 RETURN_VALUE