Is behavior of += intentional for int?

Steven D'Aprano steven at
Wed Sep 2 05:48:43 CEST 2009

On Tue, 01 Sep 2009 16:43:06 -0700, Carl Banks wrote:

>> Numbers are immutable by nature (math). The number 3.14 remains 3.14
>> whatever you try to do with it. What you call an immutable number is in
>> fact a container that contains a number.
> I wouldn't agree with that terminology or logic.

Abstract numbers aren't really "things", they're concepts, and as such I 
don't think mutable or immutable has any meaning. But if it does, then 
abstract numbers are immutable, because you can't change one into two 
without losing the value one, and that certainly doesn't happen.

> First of all "mutable number" is really just a short way to say "mutable
> number object".  

Yes, but "object" in the above doesn't necessarily mean object in the 
sense of object-oriented programming. Perhaps a better word is "mutable 
number thing", where "thing" could be an object in the OOP sense, or a 
variable in the memory-location sense, or on a stack, in a register, or 
chalk marks on a whiteboard.

> A number object in Python is not a number, it's just a
> representation of a number. Even if numbers are immutable by nature, an
> object representing a number need not be.

/s/number/abstract number/

Given that, then I agree, but given Python's implementation, you would 
need more than one change to make number's mutable, and what you would 
have wouldn't be Python any more.

> And if your number object is mutable, it does not make that object a
> container, at least not what I would call a container.  A container you
> have to dereference somehow to get at the object inside, whereas a
> mutable number object you don't dereference: it acts like number as- is.

Agreed, so long as we're talking from the programmer's perspective. From 
the compiler's perspective, or the Virtual Machine's perspective, 
variables of the type "value stored at memory location" are a kind of 
container: you don't dereference anything, but the compiler does.

There are multiple perspectives which are valid at once, depending on 
where you're looking from. A *name* is kind of a container (but not in 
the same sense that lists and dicts are containers), in that the VM has 
to dereference the name to get to the object.

> IOW, the first example below is a container, the second is not:

Do you mean the name `num` is a container, or the *contents* of `num` is 
a container? I assume you mean the contents.

> num = [2]
> num[0] += 3
> num = mutable_int(2)
> num += 3

In the sense of container that you give, I agree. But there's nothing 
magic about mutable_int() in the above -- num could be bound to a regular 
int, and it still wouldn't be a container. Obviously.

> (If you want to call the mutable number a container anyway, fine with
> me, I am not here to bicker.)  A container is sufficient to get a layer
> of indirection if that's what you want the mutable number for.
> However, the mutable number has a performance advantage over using a
> container: it avoids the overhead of creating a new object.

You're assuming that the overhead of flipping bits is less than the 
overhead of creating a new object, and that's almost certainly valid if 
the VM is implemented in (say) C. But it may not be the case if the VM is 
implemented in (say) Python, or Javascript, in which case "create a new 
object" might be less expensive than "flip a bunch of bits". If you can 
get the CPU to flip your bits, that will be fast, but perhaps your 
implementation needs to convert the int to a string of ones and zeroes, 
then perform bit-operations on those, then convert back to a real int.

(I mention this as a theoretical issue, not a serious objection to the 
existing CPython implementation. But perhaps the PyPy people have to deal 
with it?)


More information about the Python-list mailing list