It follows the Assignment statements section rules from the documentation,
assignment_stmt ::= (target_list "=")+ (expression_list | yield_expression)
If the target list is a comma-separated list of targets: The object must be an iterable with the same number of items as there are targets in the target list, and the items are assigned, from left to right, to the corresponding targets.
The object must be a sequence with the same number of items as there are targets in the target list, and the items are assigned, from left to right, to the corresponding targets.
So, when you say
[] = ""
"" is an iterable (any valid python string is an iterable) and it is being unpacked over the elements of the list.
For example,
>>> [a, b, c] = "123"
>>> a, b, c
('1', '2', '3')
Since you have an empty string, and an empty list, there is nothing to unpack. So, no error.
But, try this
>>> [] = "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
In the [] = "1" case, you are trying to unpack the string "1" over an empty list of variables. So it complains with "too many values to unpack (expected 0)".
Same way, in [a] = "" case, you have an empty string, so nothing to unpack really, but you are unpacking it over one variable, which is, again, not possible. That is why it complains "need more than 0 values to unpack".
Apart from that, as you noticed,
>>> [] = ()
also throws no error, because () is an empty tuple.
>>> ()
()
>>> type(())
<class 'tuple'>
and when it is unpacked over an empty list, there is nothing to unpack. So no error.
But, when you do
>>> "" = []
File "<input>", line 1
SyntaxError: can't assign to literal
>>> "" = ()
File "<input>", line 1
SyntaxError: can't assign to literal
as the error message says, you are trying to assign to a string literal. Which is not possible. That is why you are getting the errors. It is like saying
>>> 1 = "one"
File "<input>", line 1
SyntaxError: can't assign to literal
Internals
Internally, this assignment operation will be translated to UNPACK_SEQUENCE op code,
>>> dis(compile('[] = ""', "string", "exec"))
1 0 LOAD_CONST 0 ('')
3 UNPACK_SEQUENCE 0
6 LOAD_CONST 1 (None)
Here, since the string is empty, UNPACK_SEQUENCE unpacks 0 times. But when you have something like this
>>> 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
the sequence 123 is unpacked in to the stack, from right to left. So, the top of the stack would be 1 and the next would be 2 and the last would be 3. Then it assigns from the top of the stack to the variables from the left hand side expression one by one.
BTW, in Python, this is how you can do multiple assignments in the same expression. For example,
a, b, c, d, e, f = u, v, w, x, y, z
this works because, the right hand values are used to construct a tuple and then it will be unpacked over the left hand side values.
>>> 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
but the classic swapping technique a, b = b, a uses rotation of elements in the top of the stack. If you have only two or three elements then they are treated with special ROT_TWO and ROT_THREE instructions instead of constructing the tuple and unpacking.
>>> 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