Python3: Mutable, Immutable... everything is object!
1 >>> Introduction
In object-oriented programming languages like Python, an?object?is an entity that contains data along with associated metadata and/or functionality. In Python everything is an object, which means every entity has some metadata (called?attributes) and associated functionality (called?methods). These attributes and methods are accessed via the dot syntax.
2 >>> Id and type
A- Id :
id() is an inbuilt function in Python.
Syntax :
id(object)
Returns the identity of object. It is the address of object in memory.
It will be unique and constant throughout the lifetime of object.
Example :
>>> a = 10
>>> print("id of a",id(a))
id of a 1579869088
>>> b = "Hello World"
>>> print("id of b",id(b))
id of b 53798096
>>>
B- Type :
type() is an inbuilt function in Python.
The?type()?function returns the type of the specified object
Syntax :
Different forms of type() function in Python are:
type(object)
type(name, bases, dict)
Example 1 :
If a single argument (object) is passed to type() built-in, it returns type of the given object.
>>> a = 10
>>> print("type of a is",type(a))
type of a is <class 'int'>
>>> b = 1.2
>>> print("type of b is",type(b))
type of b is <class 'float'>
>>> c = True
>>> print("type of c is",type(c))
type of c is <class 'bool'>
>>> d = [1,2,3]
>>> print("type of d is",type(d))
type of d is <class 'list'>
>>> e = (1,2,3)
>>> print("type of e is",type(e))
type of e is <class 'tuple'>
3 >>> Mutable & immutable Objects
Definition :
Every variable in python holds an instance of an object. There are two types of objects in python i.e.?Mutable?and?Immutable objects. Whenever an object is instantiated, it is assigned a unique object id. The type of the object is defined at the runtime and it can’t be changed afterwards. However, it’s state can be changed if it is a mutable object.
To summarise the difference, mutable objects can change their state or contents and immutable objects can’t change their state or content.
A - Mutable objects :
Mutable is when something is changeable or has the ability to change. In Python, ‘mutable’ is the ability of objects to change their values. These are often the objects that store a collection of data.
=> List of Mutable objects :
?=> Mutable Objects in Python :
I believe, rather than diving deep into the theory aspects of mutable and immutable in Python, a simple code would be the best way to depict what it means in Python. Hence, let us discuss the below code step-by-step:
#Creating a list which contains name of Indian cities??
cities = [‘Delhi’, ‘Mumbai’, ‘Kolkata’]
# Printing the elements from the list cities, separated by a comma & space
for city in cities:
print(city, end=’, ’)
Output [1]: Delhi, Mumbai, Kolkata
#Printing the location of the object created in the memory address in hexadecimal format
print(hex(id(cities)))
Output [2]: 0x1691d7de8c8
#Adding a new city to the list cities
cities.append(‘Chennai’)
#Printing the elements from the list cities, separated by a comma & space?
for city in cities:
print(city, end=’, ’)
Output [3]: Delhi, Mumbai, Kolkata, Chennai
#Printing the location of the object created in the memory address in hexadecimal format
print(hex(id(cities)))
Output [4]: 0x1691d7de8c8
The above example shows us that we were able to change the internal state of the object ‘cities’ by adding one more city ‘Chennai’ to it, yet, the memory address of the object did not change. This confirms that we did not create a new object, rather, the same object was changed or mutated. Hence, we can say that the object which is a type of list with reference variable name ‘cities’ is a MUTABLE OBJECT.
=> Are lists mutable in Python?
Lists in Python are mutable data types as the elements of the list can be modified, individual elements can be replaced, and the order of elements can be changed even after the list has been created.
=> Are sets mutable in Python?
A set is an iterable unordered collection of data type which can be used to perform mathematical operations (like union, intersection, difference etc.). Every element in a set is unique and immutable, i.e. no duplicate values should be there, and the values can’t be changed. However, we can add or remove items from the set as the set itself is mutable.
=> Are strings mutable in Python?
Strings are not mutable in Python. Strings are a immutable data types which means that its value cannot be updated.
B - Immutable Objects :
Immutable Objects :?These are of in-built types like?int, float, bool, string, unicode, tuple. In simple words, an immutable object can’t be changed after it is created.
=> List of Immutable objects :
=> Immutable Objects in Python :
#Creating a Tuple which contains English name of weekdays
weekdays = ‘Sunday’, ‘Monday’, ‘Tuesday’, ‘Wednesday’, ‘Thursday’, ‘Friday’, ‘Saturday’
# Printing the elements of tuple weekdays
print(weekdays)
Output [1]: (‘Sunday’, ‘Monday’, ‘Tuesday’, ‘Wednesday’, ‘Thursday’, ‘Friday’, ‘Saturday’)
#Printing the location of the object created in the memory address in hexadecimal format
print(hex(id(weekdays)))
Output [2]: 0x1691cc35090
#tuples are immutable, so you cannot add new elements, hence, using merge of tuples with the # + operator to add a new imaginary day in the tuple ‘weekdays’
weekdays += ‘Pythonday’,
#Printing the elements of tuple weekdays
print(weekdays)
Output [3]: (‘Sunday’, ‘Monday’, ‘Tuesday’, ‘Wednesday’, ‘Thursday’, ‘Friday’, ‘Saturday’, ‘Pythonday’)
#Printing the location of the object created in the memory address in hexadecimal format
print(hex(id(weekdays)))
Output [4]: 0x1691cc8ad68
This above example shows that we were able to use the same variable name that is referencing an object which is a type of tuple with seven elements in it. However, the ID or the memory location of the old & new tuple is not the same. We were not able to change the internal state of the object ‘weekdays’. The Python program manager created a new object in the memory address and the variable name ‘weekdays’ started referencing the new object with eight elements in it.?Hence, we can say that the object which is a type of tuple with reference variable name ‘weekdays’ is an IMMUTABLE OBJECT.
Where can you use mutable and immutable objects:
Mutable objects can be used where you want to allow for any updates. For example, you have a list of employee names in your organizations, and that needs to be updated every time a new member is hired. You can create a mutable list, and it can be updated easily.
Immutability offers a lot of useful applications to different sensitive tasks we do in a network centred environment where we allow for parallel processing. By creating immutable objects, you seal the values and ensure that no threads can invoke overwrite/update to your data. This is also useful in situations where you would like to write a piece of code that cannot be modified. For example, a debug code that attempts to find the value of an immutable object.
Watch outs:?Non transitive nature of Immutability:
OK! Now we do understand what mutable & immutable objects in Python are. Let’s go ahead and discuss the combination of these two and explore the possibilities. Let’s discuss, as to how will it behave if you have an immutable object which contains the mutable object(s)? Or vice versa? Let us again use a code to understand this behaviour–
#creating a tuple (immutable object) which contains 2 lists(mutable) as it’s elements
#The elements (lists) contains the name, age & gender?
person = (['Ayaan', 5, 'Male'], ['Aaradhya', 8, 'Female'])
#printing the tuple
print(person)
Output [1]: (['Ayaan', 5, 'Male'], ['Aaradhya', 8, 'Female'])
#printing the location of the object created in the memory address in hexadecimal format
领英推荐
print(hex(id(person)))
Output [2]: 0x1691ef47f88
#Changing the age for the 1st element. Selecting 1st?element of tuple by using indexing [0] then 2nd?element of the list by using indexing [1] and assigning a new value for age as 4
person[0][1] = 4
#printing the updated tuple
print(person)
Output [3]: (['Ayaan', 4, 'Male'], ['Aaradhya', 8, 'Female'])
#printing the location of the object created in the memory address in hexadecimal format
print(hex(id(person)))
Output [4]: 0x1691ef47f88
In the above code, you can see that the object ‘person’ is immutable since it is a type of tuple. However, it has two lists as it’s elements, and we can change the state of lists (lists being mutable). So, here we did not change the object reference inside the Tuple, but the referenced object was mutated.
Same way, let’s explore how it will behave if you have a mutable object which contains an immutable object? Let us again use a code to understand the behaviour–
#creating a list (mutable object) which contains tuples(immutable) as it’s elements
list1 = [(1, 2, 3), (4, 5, 6)]
#printing the list
print(list1)
Output [1]: [(1, 2, 3), (4, 5, 6)]
#printing the location of the object created in the memory address in hexadecimal format
print(hex(id(list1)))
Output [2]: 0x1691d5b13c8
#changing object reference at index 0
list1[0] = (7, 8, 9)
#printing the list
Output [3]: [(7, 8, 9), (4, 5, 6)]
#printing the location of the object created in the memory address in hexadecimal format
print(hex(id(list1)))
Output [4]: 0x1691d5b13c8
As an individual, it completely depends upon you and your requirements as to what kind of data structure you would like to create with a combination of mutable & immutable objects. I hope that this information will help you while deciding the type of object you would like to select going forward.
Before I end our discussion on IMMUTABILITY, allow me to use the word ‘CAVITE’ when we discuss the String and Integers. There is an exception, and you may see some surprising results while checking the truthiness for immutability. For instance:
#creating an object of integer type with value 10 and reference variable name ‘x’?
x = 10
#printing the value of ‘x’
print(x)
Output [1]: 10
#Printing the location of the object created in the memory address in hexadecimal format
print(hex(id(x)))
Output [2]: 0x538fb560
#creating an object of integer type with value 10 and reference variable name ‘y’
y = 10
#printing the value of ‘y’
print(y)
Output [3]: 10
#Printing the location of the object created in the memory address in hexadecimal format
print(hex(id(y)))
Output [4]: 0x538fb560
As per our discussion and understanding, so far, the memory address for x & y should have been different, since, 10 is an instance of Integer class which is immutable. However, as shown in the above code, it has the same memory address. This is not something that we expected. It seems that what we have understood and discussed, has an exception as well.
=> Immutability of Tuple
Tuples are immutable and hence cannot have any changes in them once they are created in Python. This is because they support the same sequence operations as strings. We all know that strings are immutable. The index operator will select an element from a tuple just like in a string. Hence, they are immutable.
=> Exceptions in immutability
Like all, there are exceptions in the immutability in python too. Not all immutable objects are really mutable. This will lead to a lot of doubts in your mind. Let us just take an example to understand this.
Consider a tuple ‘tup’.
Now, if we consider tuple?tup = (‘GreatLearning’,[4,3,1,2])?;
We see that the tuple has elements of different data types. The first element here is a string which as we all know is immutable in nature. The second element is a list which we all know is mutable. Now, we all know that the tuple itself is an immutable data type. It cannot change its contents. But, the list inside it can change its contents. So, the value of the Immutable objects cannot be changed but its constituent objects can. change its value.
C - Why do mutable and immutable objects matter and how differently does Python treat them?
Numbers, strings, and tuples are immutable. Lists, dictionaries, and sets are mutable, as are most new objects you’ll code with classes.
Immutability may be used to ensure that an object remains constant throughout your program. The values of mutable objects can be changed at any time and place, whether you expect it or not.
You can change a single value of a mutable data type and it won’t change its memory address. However, you can’t change a single value of an immutable type. It will throw an error.
D - How are arguments passed to functions and what does that imply for mutable and immutable objects?
The way that the Python compiler handles function arguments has to do with whether the objects in the function arguments are mutable or not immutable.
If a mutable object is called by reference in a function, the original variable may be changed. If you want to avoid changing the original variable, you need to copy it to another variable.
When immutable objects are called by reference in a function, its value cannot be changed.
Let’s look at this Python script and guess what it will print:
def increment(n):
n += 1
b = 9
increment(b)
print(b)
Think about it and then continue reading for the answer.
The variable b refers to the object with value 9. When we pass b as a function argument to increment(n) function, the local variable n refers to the same object. However,?integers are immutable?so we need to create a new object with the value 10 and assign it to the variable n. The variable n is pointing to a different object from what b is pointing. Now, n refers to an object with value 10, but b still refers to an object with value 9. When we print(b), we get the answer 9.
The answer: 9
Let’s look at another Python script and guess what it will print:
def increment(n):
n.append(4)
my_list = [1, 2, 3]
increment(my_list)
print(my_list)
Think about it, perhaps draw a visualization, and then continue reading for the answer.
The variable my_list refers to a list object that contains references to three integers. Lists are mutable but integers are immutable. When we pass my_list as a function argument to increment(n) function, the function has the local variable n refer to the same object that my_list refers.
Since lists are mutable, the .append() method is able to modify the list in place. No new object is created and when we print my_list, we get the answer [1, 2, 3, 4].
The answer: [1, 2, 3, 4]
Let’s look at another Python script to understand more about function parameters and why mutability and immutability matter.
def assign_value(n, v):
n = v
list1 = [1, 2, 3]
list2 = [4, 5, 6]
assign_value(list1, list2)
print(list1)
Think about it and then continue reading for the answer.
We pass both lists as function parameters to the assign_value(n, v) function. The function has the local variable n refer to the same object that list1 refers, and the local variable v refers to the same object that list2 refers.
The function body reassigns n to what v is referring. Now n and v are referring to the same object.
The variables n, v, and list2 all point to the list object [4, 5, 6], while list1 still points to the list object [1 2, 3]. This is why when we print list1, we get the answer: [1, 2, 3]
The answer: [1, 2, 3]
How do we write a function that returns a copy of a list? Here’s one way of doing it. Let’s look at copy_list(l) function.
def copy_list(l):
return l[:]
my_list = [1, 2, 3]
new_list = copy_list(my_list)
We pass my_list as a function parameter to the copy_list(l) function. The function has the local variable l refer to the same object that my_list refers. When we use the slice operation [:], it creates a copy of a list and when we return that copy, we are returning the reference to that copy. Now, new_list refers to a different object than what my_list refers.
>>> def copy_list(l):
... return l[:]
...
>>> my_list = [1, 2, 3]
>>> new_list = copy_list(my_list)
>>> my_list
[1, 2, 3]
>>> new_list
[1, 2, 3]
>>> my_list == new_list
True
>>> my_list is new_list
False
>>> id(my_list) == id(new_list)
False