Note that in p1
, you are not assigning a value to list1
, which is the name of a variable local to p1
. You are actually assigning to the first element of the list
object referenced by list1
, which is the same list
object referenced by li
in the enclosing scope.
In p2
, on the other hand, i+=10
does assign a value to the local variable i
, not the variable int1
in the enclosing scope. This is because the +=
operator on objects of type int
do not actually modify the object, but return a new object instead. (That is, for an int
, i+=10
is equivalent to i = i + 10
.)
Just to show that +=
can operate on the underlying object directly, consider this function:
def p3(list1):
list1 += [10]
Then run it on a list:
>>> foo = [1,2,3]
>>> p3(list1)
>>> foo
[1, 2, 3, 10]
Here, the call list1 += [10]
is really equivalent to list1.extend([10])
, not list1 = list1 + [10]
, due to how list.__iadd__
is defined. Here, you are again not assigning a value to the name list1
, but rather invoking a method on the object referenced by list1
(which is the same object referenced by foo
).
(Update: as pointed out by user2357112, technically you do assign to list1
, but list.__iadd__
is designed to properly assign the same list back, so that the end result is that you still have a reference to the same mutable object you started with.)