Essa segue le Assignment statements section regole dalla documentazione,
assignment_stmt ::= (target_list "=")+ (expression_list | yield_expression)
Se il target list
è un elenco separato da virgole di obiettivi: L'oggetto deve essere un iterabile con lo stesso numero di elementi come ci sono bersagli nella lista di destinazione, e gli oggetti sono assegnati, da sinistra a destra, ai bersagli corrispondenti.
L'oggetto deve essere una sequenza con lo stesso numero di elementi quanti sono i target nell'elenco di destinazione e gli elementi sono assegnati, da sinistra a destra, ai target corrispondenti.
Quindi, quando si dice
[] = ""
""
è un iterabile (qualsiasi stringa Python valido è un iterabile) e viene imballati sugli elementi della lista.
Per esempio,
>>> [a, b, c] = "123"
>>> a, b, c
('1', '2', '3')
Dal momento che si dispone di una stringa vuota, e un elenco vuoto, non c'è nulla di disfare. Quindi, nessun errore.
Ma, provate questo
>>> [] = "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
Nel caso [] = "1"
, si stanno cercando di decomprimere la stringa "1"
su una lista vuota di variabili. Quindi lamenta "troppi valori da decomprimere (atteso 0)".
Allo stesso modo, nel caso [a] = ""
, si dispone di una stringa vuota, quindi nulla da decomprimere veramente, ma lo si sta decomprimendo su una variabile, che è, ancora una volta, impossibile. Ecco perché si lamenta "bisogno di più di 0 valori per decomprimere".
Oltre a questo, come avete notato,
>>> [] =()
tiri anche nessun errore, perché ()
è una tupla vuota.
>>>()
()
>>> type(())
<class 'tuple'>
e quando è scompattato su una lista vuota, non c'è nulla da disfare. Quindi nessun errore.
Ma, quando si fa
>>> "" = []
File "<input>", line 1
SyntaxError: can't assign to literal
>>> "" =()
File "<input>", line 1
SyntaxError: can't assign to literal
come il messaggio di errore dice, si sta tentando di assegnare a una stringa letterale. Che non è possibile Ecco perché stai ricevendo gli errori. E 'come dire
>>> 1 = "one"
File "<input>", line 1
SyntaxError: can't assign to literal
Internals
Internamente, l'operazione di assegnazione sarà tradotto in codice UNPACK_SEQUENCE
op,
>>> dis(compile('[] = ""', "string", "exec"))
1 0 LOAD_CONST 0 ('')
3 UNPACK_SEQUENCE 0
6 LOAD_CONST 1 (None)
Qui, dal momento che la stringa è vuota, UNPACK_SEQUENCE
decomprime 0
volte. Ma quando si ha qualcosa di simile
>>> 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 sequenza 123
viene decompresso in allo stack, da destra a sinistra. Quindi, la parte superiore della pila sarebbe 1
e la successiva sarebbe 2
e l'ultima sarebbe 3
. Quindi assegna dalla cima dello stack alle variabili dall'espressione lato sinistro una per una.
BTW, in Python, questo è il modo in cui è possibile eseguire più assegnazioni nella stessa espressione. Ad esempio,
a, b, c, d, e, f = u, v, w, x, y, z
questo funziona perché i valori destri vengono usati per costruire una tupla e quindi dovrà essere installata sui valori sinistra.
>>> 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
ma il classico scambio tecnica a, b = b, a
utilizza rotazione di elementi in cima alla pila. Se si hanno solo due o tre elementi, vengono trattati con le istruzioni speciali ROT_TWO
e ROT_THREE
invece di costruire la tupla e decomprimere.
>>> 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
È anche possibile utilizzare 'dis ('[] = ""')' 'senza chiamare la compilazione()'. –
Puoi descrivere cosa succede se stai scambiando più di tre variabili/elementi, usando il metodo nel tuo ultimo esempio? – hexafraction
@hexafraction Costruirà una nuova tupla con tutti gli elementi sul lato destro e quindi li decomprimerà sopra le variabili sul lato sinistro. – thefourtheye