In programming, immutability refers to an object whose state can not be changed after creation. Python doesn’t have any built-in functionality to support immutability. We can try to achieve this by:
Using forzenset()
Using custom classes
Using namedtuple()
frozenset()
The frozenset(iterable)
is an immutable version of a Python set. Here, iterable
can be a tuple, dictionary, or set. Consider the example below.
person = {"name": "Anne", "age": 23}person["age"]=24# Immutable iterable created from dictionaryimm_dict = frozenset(person)print(imm_dict)
Lines 1–2: We create a simple dictionary, person
, with two keys. In line 2, we change the value of age
to 24. This should work, as a Python dictionary is a mutable iterable.
Lines 5–6: We create a frozen set imm_dict
via the person
dictionary. Notice the output; it only takes the keys of the dictionary to create the frozen (immutable) set.
Another example with the set
object is as follows:
odd = {1, 3, 5, 7, 9}odd.add(11)print(odd)# Immutable iterable created from setimm_set = frozenset(odd)imm_set.add(11) # Error expected
Lines 1–3: We create a simple set, odd
, which contains odd numbers from 1 to 9. Next, we add 11 to the set using the add()
function. The print()
(line 3) verifies that a new element was added.
Lines 6–7: We create a frozen set imm_set
via the odd
set. Line 7 shows an expected error because, after creation, we can not add any new element in the imm_set
object which is a frozen (immutable) set.
To achieve immutability, we can create our class with read-only properties. Consider an example below.
# Custom class with read-only propertiesclass Immutable:def __init__(self, obj1, obj2):self._obj1 = obj1self._obj2 = obj2@propertydef obj1(self): # Getter for obj1return self._obj1@propertydef obj2(self): # Getter for obj2return self._obj2# Mainimmutable = Immutable(4, 3)print(immutable.obj1) # Reading obj1print(immutable.obj2) # Reading obj2
Lines: 3–5: The constructor implies that every object of Immutable
type will have two attributes: obj1
and obj2
.
Lines 7–9: The @property
decorator is simply a Pythonic way to use getters/setters. Here, obj1(self)
is a getter that returns the value of obj1
.
Lines 11–13: Here, obj2(self)
is a getter that returns the value of obj2
.
Lines 17–19: We create an object of Immutable
type, immutable
. Next, we simply call the getters on obj1
and obj2
, which print 4 and 3, respectively.
Note: There is no way to change the values of attributes, after an object is created.
namedtuple()
The namedtuple()
is a lightweight way to create an immutable object without creating a custom class. This function creates a simple class with named attributes. Below is an example:
# Import from collections modulefrom collections import namedtuple# Creating a namedtupleImmutable = namedtuple('Immutable', ['obj1', 'obj2'])immutable= Immutable(obj1=4, obj2=3) # Object created with type immutable (namedtuple)print(immutable.obj1)print(immutable.obj2)#immutable.obj1=5 # Error expected
Try uncommenting line 11. Notice the error because we can not change the attributes after creation.
Line 1: We import the namedtuple()
function and the collections
module.
Line 5–6: We create a namedtuple
called Immutable
with two fields: obj1
and obj2
. Next, we create an object, immutable
of Immutable
type and assign values to fields.
Line 8–9: The namedtuple
type objects are hashable. We print the values of immutable
fields, obj1
and obj2
, which print 4 and 3, respectively.
Free Resources