Clarification on Immutability please

Cameron Simpson cs at cskk.id.au
Tue Jan 21 17:15:36 EST 2020


On 21Jan2020 17:40, Stephen Tucker <stephen_tucker at sil.org> wrote:
>I am sure this has been answered many times before, but I need to ask 
>it
>again.
>
>Given that the following is valid Python 2.7.10 (when keyboarded into Idle):
>
>mytup = ("q", "w", "e")
>id(mytup)
>mytup = mytup [:2]
>id(mytup)
>
>and even that the first id(mytup) returns the same address as the second
>one,

Really? Not here:

    [~]fleet*> python2.7
    Python 2.7.16 (default, Apr  1 2019, 15:01:04)
    [GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.42.1)] on darwin
    Type "help", "copyright", "credits" or "license" for more information.
    >>> mytup = ("q", "w", "e")
    >>> id(mytup)
    4541315104
    >>> mytup = mytup [:2]
    >>> id(mytup)
    4542334880
    >>>

>I am left wondering exactly what immutability is.

Immutability generally means that the direct contents of the object may 
not be changed:

    >>> mytup = (1,2,3)
    >>> mytup[1]
    2
    >>> mytup[1] = 5
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: 'tuple' object does not support item assignment

It doesn't say anything about the contents of the internal objects:

    >>> mytup = (1, [2, 3], (4, 5))
    >>> mytup[0] = 6
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: 'tuple' object does not support item assignment
    >>> mytupl[1] = [7, 8]
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    NameError: name 'mytupl' is not defined
    >>> mytup[1].append(10)
    >>> mytup
    (1, [2, 3, 10], (4, 5))
    >>> mytup[2].append(11)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    AttributeError: 'tuple' object has no attribute 'append'

So you can see that I may modify the content of the list at mytup[1].  
However, I can't replace mytup[1] with another list, because mytup 
_itself_ is immutable.

>I am left concluding that mytup is not actually a tuple (even though type
>(mytup) tells me that it is).
>
>My only explanation is that mytup is, actually, a pointer to a tuple; the
>pointer can't change, but the contents of that pointer (or the data to
>which the pointer points) can change.

Ah. You're confusing the variable "mytup" with the object which it 
references.

"mytup" is a Python variable, which is reference to some object (a lot 
like a pointer conceptually, but not a pointer - a "pointer" is a memory 
address - so say "reference" and not "pointer" and people here will be 
happier).

Here, "mytup" refers to a tuple object. "type(mytup)" accesses that 
object and tells you its type (a tuple). You can change "mytup":

    mytup = [1, 2, 3]

which causes it to refer to a different object. By you can't change the 
direct references in the original tuple object (eg mytup[1]).

>That said, if I then type
>
>mytup = mytup + ("r", "t")
>id(mytup)
>
>I find that this third id call returns a different address from the one
>returned by the first two.

A newtuple has been created, and "mytup" and been changed to refer to 
the new object.

>Somehow, it seems, tuples can be reduced in length (from the far end)
>(which is not what I was expecting), but they cannot be extended (which I
>can understand).

No, you're seeing new tuples of different lengths. "mytup" is just being 
switched around by the assignment statement to refer to the new tuples.

If you're familiar with "pointers" in C-like languages, where a pointer 
variable holds the address of something, think of Python variables as 
somewhat like those. They're a little more complex but the behaviour is 
similar. Here "mytup" is like a pointer variable in C, and the tuple is 
the "something" to which it points. The tuple is immutable, not the 
pointer.

Why do we distinguish between "pointer" and "reference", particularly 
which CPython does a lotof this internally with C pointers (id() in 
CPython returns an address as it happens)? Because there are multiple 
implementations of Python, and they needn't use C-like pointers 
internally. Imagine the id() was an index into some table-of-objects and 
that the table itself held pointers, eg so that the object storage 
itself could be moved around.

So Python variables are references. The variables themselves are not 
immutable.

Cheers,
Cameron Simpson <cs at cskk.id.au> (formerly cs at zip.com.au)

Draw little boxes with arrows.  It helps.       - Michael J. Eager


More information about the Python-list mailing list