Respostas:
Você não está comparando por igualdade. Você está atribuindo .
Python permite que você atribua a vários destinos:
foo, bar = 1, 2
atribui os dois valores a foo
e bar
, respectivamente. Tudo o que você precisa é de uma sequência ou iterável no lado direito e uma lista ou tupla de nomes à esquerda.
Quando você faz:
[] = ""
você atribuiu uma sequência vazia (strings vazias ainda são sequências) a uma lista vazia de nomes.
É essencialmente a mesma coisa que fazer:
[foo, bar, baz] = "abc"
onde você termina com foo = "a"
, bar = "b"
e baz = "c"
, mas com menos caracteres.
Você não pode, entretanto, atribuir a uma string, portanto, ""
no lado esquerdo de uma atribuição nunca funciona e é sempre um erro de sintaxe.
Consulte a documentação das declarações de atribuição :
Uma instrução de atribuição avalia a lista de expressões (lembre-se de que pode ser uma única expressão ou uma lista separada por vírgulas, a última produzindo uma tupla) e atribui o único objeto resultante a cada uma das listas de destino, da esquerda para a direita.
e
A atribuição de um objeto a uma lista de destino, opcionalmente entre parênteses ou colchetes , é definida recursivamente como segue.
Ênfase minha .
O fato de o Python não gerar um erro de sintaxe para a lista vazia é, na verdade, um pequeno bug! A gramática oficialmente documentada não permite uma lista de alvos vazia e, para o vazio, ()
você obtém um erro. Veja bug 23275 ; é considerado um bug inofensivo:
O ponto de partida é reconhecer que isso existe há muito tempo e é inofensivo.
Veja também Por que é válido atribuir a uma lista vazia, mas não a uma tupla vazia?
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()
.