My apologies for the length of this post, but I decided to choose the completeness.
Once you know a few basic rules, they are not difficult to generalize. I will do my best to explain a few examples. Since you are talking about evaluating these “manually,” I will offer some simple replacement rules. Basically, it might be easier for you to understand the expression if all iterations are formatted in the same way.
Only for unpacking on the right side of = (i.e. for rvalues) the following substitutions are valid:
'XY' -> ('X', 'Y') ['X', 'Y'] -> ('X', 'Y')
If you find that the value is not decompressed, you will cancel the replacement. (See below for more details).
Also, when you see bare commas, pretend to be a top-level tuple there. Do this on both the left and right sides (i.e. for lvalues and rvalues):
'X', 'Y' -> ('X', 'Y') a, b -> (a, b)
Given these simple rules, here are a few examples:
(a,b), c = "XY", "Z" # a = 'X', b = 'Y', c = 'Z'
Applying the above rules, we convert "XY" to ('X', 'Y') and cover the bare commas in parens:
((a, b), c) = (('X', 'Y'), 'Z')
The visual correspondence here makes it pretty obvious how the assignment works.
Here is an erroneous example:
(a,b), c = "XYZ"
Following the above replacement rules, we get the following:
((a, b), c) = ('X', 'Y', 'Z')
This is clearly a mistake; nested structures do not match. Now let's see how this works for a slightly more complex example:
(a,b), c, = [1,2],'this'
Applying the above rules, we get
((a, b), c) = ((1, 2), ('t', 'h', 'i', 's'))
But now it’s clear from the structure that 'this' not unpacked, but directly assigned c . Therefore, we are canceling the replacement.
((a, b), c) = ((1, 2), 'this')
Now let's see what happens when we complete c in the tuple:
(a,b), (c,) = [1,2],'this'
becomes
((a, b), (c,)) = ((1, 2), ('t', 'h', 'i', 's'))
Again, the error is obvious. c no longer a bare variable, but a variable inside the sequence, so the corresponding sequence on the right is unpacked in (c,) . But the sequences have different lengths, so there is an error.
Now for extended unpacking using the * operator. This is a little trickier, but still pretty simple. The variable preceding * becomes a list that contains any elements from the corresponding sequence that are not assigned to variable names. Starting with a pretty simple example:
a, *b, c = "X...Y" # a = 'X', b = ['.','.','.'], c = 'Y'
It is getting
(a, *b, c) = ('X', '.', '.', '.', 'Y')
The easiest way to analyze this is to work from the end. 'X' assigned a , and 'Y' assigned c . The remaining values in the sequence are put into the list and assigned b .
Lvalues such as (*a, b) and (a, *b) are just the special cases above. You cannot have two * statements inside the same lvalue sequence, because it will be ambiguous. Where the values will look something like this: (a, *b, *c, d) - in b or c ? I will consider the enclosed case in an instant.
*a = 1
Here the error is pretty clear. The target ( *a ) must be in the tuple.
*a, = (1,2)
This works because there is a bare comma. Applying rules ...
(*a,) = (1, 2)
Since there are no variables except *a , *a pulls out all the values in the rvalue sequence. What if you replace (1, 2) with one value?
*a, = 1
becomes
(*a,) = 1
Again, the error here is self-explanatory. You cannot unpack what is not a sequence, but *a need to unpack something. Therefore we put it in sequence
*a, = [1]
Which is equivalent
(*a,) = (1,)
Finally, this is a common point of embarrassment: (1) same as 1 - you need a comma to distinguish a tuple from an arithmetic statement.
*a, = (1)
Now for nesting. Actually this example was not in your "NESTED" section; maybe you didn’t understand that it was nested?
(a,b), *c = 'XY', 2, 3
becomes
((a, b), *c) = (('X', 'Y'), 2, 3)
The first value in the top-level court is assigned, and the remaining values in the top-level court ( 2 and 3 ) are assigned c - as you would expect.
(a,b),c = 1,2,3
I already explained why the first line causes an error. The second line is stupid, but here's why it works:
(*(a, b), c) = (1, 2, 3)
As explained earlier, we work with the ends. 3 , c assigned, and then the remaining values are assigned to the variable with the preceding * , in this case (a, b) . Thus, which is equivalent to (a, b) = (1, 2) , which works because there is the correct number of elements. I can’t think of any reason that has ever appeared in working code. Similarly
*(a, *b), c = 'this'
becomes
(*(a, *b), c) = ('t', 'h', 'i', 's')
Work with ends, 's' is assigned to c , and ('t', 'h', 'i') is assigned (a, *b) . Working again from the end, 't' is assigned a , and ('h', 'i') is assigned b as a list. This is another stupid example that should never appear in working code.