It's documented to count the elements on the right in perlop (the last sentence in the Assignment Operators section):
Similarly, a list assignment in list context produces the list of lvalues assigned to, and a list assignment in scalar context returns the number of elements produced by the expression on the right hand side of the assignment.
The reason it works like that is so that you can write things like this:
If it counted the number of elements on the left hand side of the assignment, that would be an infinite loop.
If you think about it, the number of elements on the left hand side is either the same as on the right hand side or it's a constant (when you're assigning to a list of scalars). In the first case, it makes no difference which side you count, and in the second case, counting the right hand side is more useful.
On the other hand, in list context the assignment operator returns the left hand list, because that's more useful. If you use it in a context that modifies the list elements, you want to modify the variables that were just assigned to.
Re: your comment In your example, is a two-element list, which is why the assignment operator returns 2. When you assign a shorter list to a longer list of scalars, the right hand side is not "padded out" with before the assignment happens. Instead, any variables that did not have a value associated with them from the right hand list are reset to their default value. For a scalar variable, that's . For arrays, that's an empty array. For hashes, that's an empty hash.
Python: copying a list the right way
Those proficient in Python know what the previous line do. It copies the list into . This is confusing for beginners and should be avoided. Sadly the notation is widely used, probably because most Python programmers don’t know a better way of copying lists.
A little bit of pythonic theory
First we need to understand how Python manages objects & variables. Python doesn’t have variables like C. In C a variable is not just a name, it is a set of bits; a variable exists somewhere in memory. In Python variables are just tags attached to objects.
Consider the following statement:
It means that points to the list we just created, but is not the list. If we do:
We didn’t copy the list referenced by . We just created a new tag and attached it to the list pointed by . Like in the picture below:
If you modify , you also modify , since they point to the same list:
The built-in function helps keeping track of all this. It returns the object’s unique id. This id is the object’s memory address.
and really do point to the same memory address. points to a new empty list, different from the one referenced by and .
Back to our list
Now we want to copy the list referenced by . We need to create a new list to attach to it.
That bring use back to . The operator returns a slice of a sequence. Slicing a portion of a list: create a new list, and copy the portion of the original list into this new list.
If you omit the first index, the slice starts at the beginning of the list; omit the second index, it stops at the end of the list.
By calling , you get a slice of starting from the beginning and finishing at the end. That’s a full copy of . But it’s not the only way of copying lists. What about this one?
Isn’t it better, less cryptic, and more pythonic? feels a bit too much like Perl. Unlike with the slicing notation, those who don’t know Python will understand that contains a list.
is the constructor. It will construct a new list based of the passed sequence. The sequence doesn’t necessarily need to be a list, it can be any kind of sequence.
And it works with generators. doesn’t work on generators since they are unsubscriptable —you can’t do generator, for example.
90% of the time could be replaced by . Of course it won’t work for everything since the two are not strictly equivalent, but it is worth trying. Next time you see a try to replace it with , your code should be more readable. Do it, the devil is in the details.