Ele segue as regras da seção de declarações de atribuição da documentação,
assignment_stmt ::= (target_list "=")+ (expression_list | yield_expression)
Se target list
for uma lista de alvos separados por vírgula: O objeto deve ser iterável com o mesmo número de itens que os alvos na lista de alvos, e os itens são atribuídos, da esquerda para a direita, aos alvos correspondentes.
O objeto deve ser uma sequência com o mesmo número de itens que os alvos na lista de alvos, e os itens são atribuídos, da esquerda para a direita, aos alvos correspondentes.
Então, quando você diz
[] = ""
""
é iterável (qualquer string Python válida é iterável) e está sendo descompactada sobre os elementos da lista.
Por exemplo,
>>> [a, b, c] = "123"
>>> a, b, c
('1', '2', '3')
Como você tem uma string vazia e uma lista vazia, não há nada para desempacotar. Então, nenhum erro.
Mas, tente isso
>>> [] = "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
Nesse [] = "1"
caso, você está tentando desempacotar a string "1"
em uma lista vazia de variáveis. Portanto, ele reclama com "muitos valores para desempacotar (esperado 0)".
Da mesma forma, no [a] = ""
caso, você tem uma string vazia, então nada para descompactar realmente, mas você está descompactando sobre uma variável, o que, novamente, não é possível. É por isso que ele reclama "precisa de mais de 0 valores para descompactar".
Além disso, como você notou,
>>> [] = ()
também não lança nenhum erro, porque ()
é uma tupla vazia.
>>> ()
()
>>> type(())
<class 'tuple'>
e quando ele é descompactado em uma lista vazia, não há nada para desempacotar. Portanto, nenhum erro.
Mas, quando você faz
>>> "" = []
File "<input>", line 1
SyntaxError: can't assign to literal
>>> "" = ()
File "<input>", line 1
SyntaxError: can't assign to literal
como diz a mensagem de erro, você está tentando atribuir a um literal de string. O que não é possível. É por isso que você está recebendo os erros. É como dizer
>>> 1 = "one"
File "<input>", line 1
SyntaxError: can't assign to literal
Internos
Internamente, esta operação de atribuição será traduzida para o UNPACK_SEQUENCE
código op,
>>> dis(compile('[] = ""', "string", "exec"))
1 0 LOAD_CONST 0 ('')
3 UNPACK_SEQUENCE 0
6 LOAD_CONST 1 (None)
Aqui, como a string está vazia, UNPACK_SEQUENCE
desempacota 0
vezes. Mas quando você tem algo assim
>>> 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
a sequência 123
é descompactada na pilha, da direita para a esquerda. Portanto, o topo da pilha seria, 1
o próximo seria 2
e o último seria 3
. Em seguida, ele atribui do topo da pilha às variáveis da expressão do lado esquerdo, uma por uma.
BTW, em Python, é assim que você pode fazer várias atribuições na mesma expressão. Por exemplo,
a, b, c, d, e, f = u, v, w, x, y, z
isso funciona porque os valores do lado direito são usados para construir uma tupla e então ela será desempacotada sobre os valores do lado esquerdo.
>>> 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
mas a técnica clássica de troca a, b = b, a
usa rotação de elementos no topo da pilha. Se você tiver apenas dois ou três elementos, eles serão tratados com instruções especiais ROT_TWO
e em ROT_THREE
vez de construir a tupla e desempacotar.
>>> 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
dis('[] = ""')
sem ligarcompile()
.