python - []=(),()=(), y{}=() ''asignaciones''
python-3.x python-2.7 (4)
El lado izquierdo de una instrucción de asignación no es una expresión, es una lista de objetivos . Breve resumen:
- Si la lista de objetivos es un identificador, el nombre solo está vinculado al lado derecho.
- Si la lista de objetivos es una lista de objetivos separados por comas, se desempaqueta el lado derecho y los elementos desempaquetados se asignan a los objetivos enumerados.
- Una lista de objetivos puede estar entre paréntesis o corchetes. En particular, eso permite crear listas de objetivos vacías, como se ve en sus ejemplos.
Esto explica por qué []
y ()
son lados izquierdos válidos para las asignaciones: son listas de objetivos válidas. Sin embargo, {}
no lo es, ya que no es una lista de objetivos válida.
Por supuesto, {}
podría ser parte de un objetivo, por ejemplo, como el principal de una suscripción: {}[()] = 0
es python válido (pero completamente inútil, por supuesto).
Me sorprendió encontrar lo siguiente, en Python 3, los primeros dos no recaudan nada:
>>> [] = ()
>>> () = ()
>>> {} = ()
File "<stdin>", line 1
SyntaxError: can''t assign to literal
En Python 2.7, solo el primero no genera nada:
>>> [] = ()
>>> () = ()
File "<stdin>", line 1
SyntaxError: can''t assign to ()
>>> {} = ()
File "<stdin>", line 1
SyntaxError: can''t assign to literal
¿Que esta pasando aqui? ¿Por qué algunos de ellos no generan errores? ¿Y por qué supuestamente se agregó () = ()
para ser válido en Python 3?
* Tenga en cuenta que puede reemplazar el lado derecho con cualquier iterable vacío (por ejemplo, [] = set()
), simplemente elijo una tupla vacía para la ilustración
Esta es la sintaxis para descomprimir un iterable de dos elementos en dos objetivos de asignación:
[x, y] = whatever
Esto generaliza hasta tres o más objetivos, pero también se generaliza hacia abajo:
[x] = whatever
descomprime un iterable de un elemento en un objetivo de asignación, y
[] = whatever
descomprime un elemento cero iterativo en objetivos de asignación cero (que no hace nada si whatever
que whatever
es iterable en un elemento cero, y arroja una excepción si no lo es).
() = whatever
también descomprime un iterable de elemento cero, pero {} = whatever
que no; no hay una sintaxis de asignación de desembalaje que implique llaves.
Hay una manera de asignar variables de un iterable:
>>> a, b = iter((1, 2))
>>> a
1
>>> b
2
>>> [c, d] = iter((4, 5))
>>> c
4
>>> d
5
Las asignaciones [] = …
y () = …
parecen ser casos especiales de estos.
Según Issue23275 , estos son básicamente peculiaridades que no causan daño real, pero tampoco utilidad. Tenga en cuenta que [] = ()
no altera el literal de la list
:
>>> [] = ()
>>> type([])
<class ''list''>
[] = x
declaraciones básicamente afirman que x
es iterable y que x
está vacío (aunque nadie recomendaría usarlos de esta manera), por ejemplo
>>> [] = (1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: ''int'' object is not iterable
>>> [] = (1,)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: too many values to unpack
Como comenta John Y , es mejor pensar que [] = ()
no es una tarea, sino una forma de ser consistente con la sintaxis de desempaquetado iterativo de Python.
Como comenta ArrowCase , esta sintaxis también se extiende a múltiples asignaciones:
>>> a = [] = ()
>>> a
()
Al observar el bytecode CPython de la asignación múltiple, se ilustra que estas operaciones son similares a la sintaxis de desempaquetado iterable normal, utilizando la instrucción UNPACK_SEQUENCE
:
>>> dis.dis(''a = [] = ()'')
1 0 BUILD_TUPLE 0
2 DUP_TOP
4 STORE_NAME 0 (a)
6 UNPACK_SEQUENCE 0
8 LOAD_CONST 0 (None)
10 RETURN_VALUE
>>> dis.dis(''[a, b] = (1, 2)'')
1 0 LOAD_CONST 3 ((1, 2))
2 UNPACK_SEQUENCE 2
4 STORE_NAME 0 (a)
6 STORE_NAME 1 (b)
8 LOAD_CONST 2 (None)
10 RETURN_VALUE
El mismo Issue23275 establece que () = ()
se agregó como sintaxis válida a Python 3 para concordancia. Se decidió que quitar [] = ()
rompería innecesariamente el código, ya que no causa daños y se ajusta a la lógica de desempaquetado iterable. {} = ()
todavía no es válido porque la sintaxis de desempaquetado no tiene sentido en este contexto con llaves.
En caso de que alguien se esté preguntando, la sintaxis como list() = ()
simplemente no es sintácticamente válida, porque nunca se puede asignar a la función de llamada.