Python3: Mutable, Immutable… everything is object!
What is Python?
Python is a popular general-purpose programming language that can be used for a wide variety of applications. It includes high-level data structures, dynamic typing, dynamic binding, and many more features that make it as useful for complex application development as it is for scripting or “glue code” that connects components together. It can also be extended to make system calls to almost all operating systems and to run code written in C or C++. Due to its ubiquity and ability to run on nearly every system architecture, Python is a universal language found in a variety of different applications.
Everything is an object
Unlike other programming languages where the language supports objects, in Python really everything is an object — including integers, lists, and even functions.
An object is a fundamental building block of an object-oriented language. Integers, strings, floating point numbers, even arrays and dictionaries, are all objects. More specifically, any single integer or any single string is an object. The number 12 is an object, the string “hello, world” is an object, a list is an object that can hold other objects, and so on. You’ve been using objects all along and may not even realize it.
Objects have types
Every object has a type, and that type defines what you can do with the object. For example, the int
type defines what happens when you add something to an int, what happens when you try to convert it to a string, and so on.
Conceptually, if not literally, another word for type is class. When you define a class, you are in essence defining your own type. Just like 12
is an instance of an integer, and "hello world"
is an instance of a string, you can create your own custom type and then create instances of that type. Each instance is an object.
id
(object)
this is a function thet return the “identity” of an object. This is an integer which is guaranteed to be unique and constant for this object during its lifetime. Two objects with non-overlapping lifetimes may have the same id value.
CPython implementation detail: This is the address of the object in memory.
Immutable objects in Python
For some types in Python, once we have created instances of those types, they never change. They are immutable.
The following are some immutable objects:
- int
- float
- decimal
- complex
- bool
- string
- tuple
- range
- frozenset
- bytes
For example, int
objects are immutable in Python. What will happen if we try to change the value of an int
object?
Well, it seems that we changed x
successfully. This is exactly where many people get confused. What exactly happened under the hood here? Let's use id
to further investigate:
So we can see that by assigning x = 24602
, we didn't change the value of the object that x
had been bound to before. Rather, we created a new object, and bound the name x
to it.
So after assigning 24601
to x
by using x = 24601
, we had the following state:
And after using x = 24602
, we created a new object, and bound the name x
to this new object. The other object with the value of 24601
is no longer reachable by x
(or any other name in this case):
Whenever we assign a new value to a name (in the above example — x
) that is bound to an int
object, we actually change the binding of that name to another object.
The same applies for tuple
s, strings (str
objects), and bool
s as well. In other words, int
(and other number types such as float
), tuple
, bool
, and str
objects are immutable.
Let’s test this hypothesis. What happens if we create a tuple
object, and then give it a different value?
Just like an int
object, we can see that our assignment actually changed the object that the name my_tuple
is bound to.
What happens if we try to change one of the tuple
's elements?
As we can see, Python doesn’t allow us to modify my_tuple
's contents, as it is immutable.
Mutable objects in Python
The following are some mutable objects:
- list
- dict
- set
- bytearray
- user-defined classes (unless specifically made immutable)
Some types in Python can be modified after creation, and they are called mutable. For example, we know that we can modify the contents of a list
object:
Does that mean we actually created a new object when assigning a new value to the first element of my_list
? Again, we can use id
to check:
So our first assignment my_list = [1, 2, 3]
created an object in the address 55834760
, with the values of 1
, 2
, and 3
:
We then modified the first element of this list
object using my_list[0] = 'a new value'
, that is - without creating a new list
object:
Now, let us create two names — x
and y
, both bound to the same list
object. We can verify that either by using is
, or by explicitly checking their id
s:
What happens now if we use x.append(3)
? That is, if we add a new element (3
) to the object by the name of x
?
Will x
by changed? Will y
?
Well, as we already know, they are basically two names of the same object:
Since this object is changed, when we check its names we can see the new value:
Note that x
and y
have the same id
as before – as they are still bound to the same list
object:
In addition to list
s, other Python types that are mutable include set
s and dict
s.
Conclusion
- Mutable and immutable objects are handled differently in python. Immutable objects are quicker to access and are expensive to change because it involves the creation of a copy.
Whereas mutable objects are easy to change. - Use of mutable objects is recommended when there is a need to change the size or content of the object.
- Exception : However, there is an exception in immutability as well. We know that tuple in python is immutable. But the tuple consists of a sequence of names with unchangeable bindings to objects.
Consider a tuple
The tuple consists of a string and a list. Strings are immutable so we can’t change its value. But the contents of the list can change. The tuple itself isn’t mutable but contain items that are mutable.