a wierd parameter passing behavior

Michael Chermside mcherm at mcherm.com
Wed Jun 4 11:35:33 EDT 2003


thomas writes:
> I think it is better coding style to use append() than the
> plus operator on lists. 

Actually, it's not better coding style any more than using "x * 2"
is better coding style than "x + 3" ... they do different
things (well, unless x is 6).

Performing "myList.append('x')" changes the list referred to by
the variable myList. Executing the expression "myList + ['x']"
has no affect on the list referred to by the variable myList, but
it DOES create a NEW list which is based on that list.

This line:
    myList.append('x')  # line 1
and this one:
    myList = myList + ['x']  # line 2

do different things. For one thing, if any other references 
exist to the list "myList" is bound to, then they will see changes
when line 1 is executed, but won't see changes when line 2 is
run. For another thing, executing line 1 probably won't allocate
new memory (if there's space to extend the list in place), but
executing line 2 will *definitely* allocate new memory. Another
minor detail is that id(myList) will be unchanged by line 1 and
will be changed by line 2. All of these things are related, and
they make sense when you realize that line 1 modifies the list
in place and line 2 makes a new list.

There's nothing confusing at all until you try executing THIS:
    myList += ['x']   # line 3
Once upon a time, Python didn't have the augmented assignment
statements (the +=, -=, *=, etc). Back in those days, people
had to be very explicit about whether they wanted to modify
in place (line 1) or create a new object (line 2). But lots of
folks came from C or Java and griped about not having the 
augmented assignments. They were thinking mostly about simple
types like numbers or strings. In Python, these are immutable...
so code gets written like this:
    myInteger = myInteger + 3   # just like line 2
but you can't write this:
    myInteger.increment_in_place(3)   # this line doesn't work!
because integers don't have any methods for changing them in
place. So with immutable objects, there's one unambiguous
meaning for "x += y"... the make-a-new-object one (line 2).

Guido was very reluctant, but eventually he gave in and added
augmented assignment to the language. In the case of immutable
types, it was obvious what the augmented assignment should do,
but in the case of mutable types (like lists) there were the
two choices... should it change things in place, or should it
create a new object. Since new objects are created for immutable
types, consistancy suggests that it should do the same for
mutable objects, but the problem is, that's almost never what
you actually want! For lists, particularly long lists, executing
line 2 can take hundreds of times (or more!) longer than executing
line 1. And _IF_ (it's a big if) "myList" is the ONLY reference
to that object, then the two are "pretty much" equivalent.

So Guido invoked "practicality beats purity", and declared that
for mutable types (particularly lists), the augmented assignments
would mutate in place (where possible), but for immutable types
it would create new objects. The result is that code using "+="
on lists runs enormously faster, but that unfortunately people
like Torvo Sollazzo occasionally get bit by this unexpected difference.

-- Michael Chermside








More information about the Python-list mailing list