Jest zgodny z zasadami sekcji Instrukcje przypisania z dokumentacji,
assignment_stmt ::= (target_list "=")+ (expression_list | yield_expression)
Jeśli target list
jest to lista celów rozdzielonych przecinkami: obiekt musi być iterowalny i zawierać taką samą liczbę elementów, jak cele na liście celów, a elementy są przypisane, od lewej do prawej, do odpowiednich celów.
Obiekt musi być sekwencją z taką samą liczbą elementów, jak liczba celów na liście celów, a elementy są przypisane, od lewej do prawej, do odpowiednich celów.
Więc kiedy mówisz
[] = ""
""
jest iterowalny (każdy poprawny łańcuch w Pythonie jest iterowalny) i jest rozpakowywany po elementach listy.
Na przykład,
>>> [a, b, c] = "123"
>>> a, b, c
('1', '2', '3')
Ponieważ masz pusty ciąg i pustą listę, nie ma nic do rozpakowania. Więc nie ma błędu.
Ale spróbuj tego
>>> [] = "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
W takim [] = "1"
przypadku próbujesz rozpakować łańcuch "1"
na pustej liście zmiennych. Więc narzeka z "zbyt wieloma wartościami do rozpakowania (oczekiwane 0)".
Tak samo, w [a] = ""
przypadku, gdy masz pusty ciąg, więc nie ma nic do rozpakowania, ale rozpakowujesz go na jedną zmienną, co znowu jest niemożliwe. Dlatego narzeka, że „do rozpakowania potrzeba więcej niż 0 wartości”.
Poza tym, jak zauważyłeś,
>>> [] = ()
również nie zgłasza błędu, ponieważ ()
jest pustą krotką.
>>> ()
()
>>> type(())
<class 'tuple'>
a kiedy jest rozpakowywany na pustej liście, nie ma nic do rozpakowania. Więc nie ma błędu.
Ale kiedy to zrobisz
>>> "" = []
File "<input>", line 1
SyntaxError: can't assign to literal
>>> "" = ()
File "<input>", line 1
SyntaxError: can't assign to literal
jak mówi komunikat o błędzie, próbujesz przypisać do literału łańcuchowego. Co nie jest możliwe. Dlatego otrzymujesz błędy. To jak mówienie
>>> 1 = "one"
File "<input>", line 1
SyntaxError: can't assign to literal
Wewnętrzne
Wewnętrznie ta operacja przypisania zostanie przetłumaczona UNPACK_SEQUENCE
na kod operacyjny ,
>>> dis(compile('[] = ""', "string", "exec"))
1 0 LOAD_CONST 0 ('')
3 UNPACK_SEQUENCE 0
6 LOAD_CONST 1 (None)
Tutaj, ponieważ ciąg jest pusty, UNPACK_SEQUENCE
rozpakowuje 0
razy. Ale kiedy masz coś takiego
>>> 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
sekwencja 123
jest wypakowywana na stos, od prawej do lewej. Tak więc, szczyt stosu byłby, 1
następny byłby 2
i ostatni byłby 3
. Następnie przypisuje z góry stosu zmienne z wyrażenia po lewej stronie, jeden po drugim.
Przy okazji, w Pythonie w ten sposób można wykonać wiele przypisań w tym samym wyrażeniu. Na przykład,
a, b, c, d, e, f = u, v, w, x, y, z
to działa, ponieważ wartości po prawej stronie są używane do konstruowania krotki, a następnie zostaną rozpakowane na wartościach po lewej stronie.
>>> 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
ale klasyczna technika zamiany a, b = b, a
wykorzystuje rotację elementów na szczycie stosu. Jeśli masz tylko dwa lub trzy elementy, zamiast konstruowania krotki i rozpakowywania są traktowane specjalnymi instrukcjami ROT_TWO
i ROT_THREE
instrukcjami.
>>> 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('[] = ""')
bez dzwonieniacompile()
.