Tuples and immutability

Steven D'Aprano steve+comp.lang.python at pearwood.info
Mon Mar 10 10:13:40 CET 2014

On Mon, 10 Mar 2014 02:35:36 -0600, Ian Kelly wrote:

> On Sun, Mar 9, 2014 at 8:37 PM, Steven D'Aprano
> <steve+comp.lang.python at pearwood.info> wrote:
>> On Sun, 09 Mar 2014 17:42:42 -0600, Ian Kelly wrote:
>>> On Sun, Mar 9, 2014 at 4:03 PM, Gregory Ewing
>>> <greg.ewing at canterbury.ac.nz> wrote:
>>>> Note that it says "when possible", not "if the implementation feels
>>>> like it".
>>> That's quite vague, and not much stronger a guarantee than "maybe".
>>> It's technically "possible" for this augmented assignment to be
>>> performed in place:
>>> x = 12
>>> x += 4
>>> But it's not done in-place, because ints are meant to be immutable.
>> That's incorrect. Ints aren't merely "meant" to be immutable, which
>> implies that's it's optional, they are defined by the language
>> specification and the reference implementation as immutable. Any
>> interpreter where ints are mutable *is not Python*.
> That's true, but is beside the point, which is that "when possible" is
> not very meaningful.

It's meaningful. It refers not to ints, but the infinite number of 
possible classes which might include augmented assignment. Some of them 
will be immutable, in which case it is not possible for += etc. to be 
performed in-place. Some of them will be mutable, but there won't be any 
reasonable (or even unreasonable) way to perform += in-place.

But for some mutable classes, it will be possible to perform += in place, 
in which case the docs say that they have to do so.

>>> In any case, this means that whether the operation is actually
>>> performed in-place is an implementation detail -- if not of the Python
>>> implementation then at least of the class -- and not something the
>>> user should take for granted.
>> Whether += operates in place or not is part of the interface of the
>> class, not the implementation.
>> Would you say that whether list.append operates in place or creates a
>> new list is an implementation detail? Whether str.upper() creates a new
>> string or modifies the existing one in place?
> Of course not.  list.append is documented as modifying the list.
> str.upper is documented as returning a copy of the string.

Right. And += is documented as modifying the list too.

>> Mutability versus
>> immutability is part of the interface, not implementation, not
>> withstanding that somebody could create an alternative class with the
>> opposite behaviour: a MutableStr, or ImmutableList.
> If the in-place behavior of += is held to be part of the interface, then
> we must accept that += is not polymorphic across mutable and immutable
> types, 

I'm fine with that.

> which in my mind largely* defeats the purpose of having it. 

Not to my mind. I think that having augmented assignment is worthwhile 
even if it behaves differently and incompatibly for different classes. 
After all, so does * (multiplication):

py> x = 24
py> x*x


py> x = []
py> x*x
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can't multiply sequence by non-int of type 'list'

I don't think that we ought to throw away * and I don't think we ought to 
throw away *= either.

> After all, there should be one -- and preferably only one -- obvious way
> to do it.  If you want in-place concatenation, the obvious way to do it
> is by calling extend.  If you want copy concatenation, the obvious way
> to do it is with the + operator.  Why then should not just mutable
> sequences but immutable sequences as well even offer the += operator?


I can see that each individual operation:

    list +
    list += 

makes good sense in isolation, but I can also see that the combination 
don't quite gel together as smoothly as we might hope.

Steven D'Aprano

More information about the Python-list mailing list