The (im)mutable in Python

Lucia Rodriguez
5 min readMay 29, 2019

Projects at Holberton School passes really fast and sometimes it’s really hard to catch up with its rhythm. At this moment we’re learning Python and as a programming language is really catchy and personally I’ve enjoyed learning it. Through Python we’ve started to learn Object Oriented Programming (OOP), but… What is OOP? Well, using OOP you’re able to wrap all functions and data structures into something we call object. You’re able to create classes (something like a mold with some attributes common to all the individuals which match with this class), and functions (actions that the specimens are able to perform). Given attributes and functions in a class, we’re able to create objects with those attributes and able to perform those very functions. Focusing in the function section, we noted that variables can behave differently after they are used in a function as an argument, and that’s because of their type. For checking this behavior id() and type() can be really useful.

id() and type()

Output of help(id) — What “id” is for Python
What “id” is for type()

Both of them are built-in of Python. id() , on one hand, is a built-in function that returns the identity (an integer number) of a given argument, something similar with memory address of a variable or function in C. While running a program, it’s not possible that 2 or more different variables (in value at least), share the same identity. On the other side, type() returns the type of a variable or constant in Python. At this point you can see a keyword on its returning: class. So, we learned that there is a kind of metaclass called Object in Python and Python’s different types are different classes of that Object with their own attributes.

Output of help(type) — What “type” means for Python
What “type” means for type()

Mutable objects:

In Python there are objects that their values can be accessed, read and modified while saving its original identity, like lists and dictionaries. For a better comprehension of this, you can try the following examples:

>>> list = [1, 2, 3]
>>> id(list)
140227669870984
>>> list += [4]
>>> print(list)
[1, 2, 3, 4]
>>> id(list)
140227669870984
>>>

You can use the methods (functions) of the class to modify it. On the following example you can check what happens to identity when you use the .append of the object list:

>>> list = [1, 2, 3]
>>> id(list)
140227669870856
>>> list.append([6])
>>> print(list)
[1, 2, 3, [6]]
>>> id(list)
140227669870856
>>>

Same behavior can be observed when we use .pop of list :

>>> list = [1, 2, 3]
>>> id(list)
140227669870856
>>> list.append([6])
>>> print(list)
[1, 2, 3, [6]]
>>> id(list)
140227669870856
>>> list.pop()
[6]
>>> id(list)
140227669870856
>>>

Immutable Objects:

By analogy we can intuit that the immutable objects are those that can be accessed but not modified saving their identity after their creation. You can check how it works through the following examples:

>>> a = 5
>>> id(a)
10105216
>>> a += 1
>>> print(a)
6
>>> id(a)
10105248
>>>

Note that you have an identity for the initial a and you get another one when you increment it.

>>> a = “Holberton”
>>> id(a)
140227669456560
>>> b = “School”
>>> id(b)
140227712927144
>>> a += b
>>> print(a)
HolbertonSchool
>>> id(a)
140227669456432
>>>

Note that the identity for a is different before and after the += operation. Every time you make a change in the value of the variable, a new object is generated and the variable points to it, so this is the reason of getting a new identity after every modification on it.

Why does (im)mutability matters?

Python handles mutable and immutable objects differently. For int objects, for example, Python will take a copy of the variable when it is the case. For list objects, on the other side, will be modified using its very own identity.

And what about functions?

There are two ways to pass an argument into a Python function: call by value (using a local copy) and call by reference (the variable itself). Mutability properties are important because it is possible to modify or not an argument using a function. Check this out:

>>> a = 45
>>> id(a)
10106496
>>> b = 65
>>> id(b)
10107136>>> def suma(a, b):
… a = a + b

>>> suma(a, b)
>>> print(a)
45
>>> id(a)
10106496
>>>

Note that, even if at inside of the function there’s a new assignment of a, after the execution of suma its value and identity hasn’t changed. Even if the operator in the function is +=, it doesn’t change.

Something different happens if you’re working with a mutable object like lists. Check this example:

>>> lista = [1, 2, 3]
>>> listb = [4, 5, 6]
>>> id(lista)
139787562211720
>>> id(listb)
139787522624328
>>> def sumalistas(x, y):
… lista = lista + listb

>>> print(lista)
[1, 2, 3]
>>> id(lista)
139787562211720
>>>

Check this other example:

>>> lista = [1, 2, 3]
>>> def cambiolista(lista):
… lista = [65, 67]

>>> cambiolista(lista)
>>> print(lista)
[1, 2, 3]

Even if you assign again, no changes were made.

Finally, check this final example:

>>> lista = [1, 2, 3]
>>> listb = [4, 5, 6]
>>> def cambiolista(lista, listab):
… lista += listab

>>> cambiolista(lista, listb)
>>> print(lista)
[1, 2, 3, 4, 5, 6]

Using += you can get a change in the value of lista .

Final, fun yet pivotal fact: did you know that all numbers from -5 to 256 in Python are setted once Python interpreter is running, so their identities are the same in all the machines?

--

--