python python-3.x python-2.7

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.