In Java, the ‘final’ keyword is used for variables that cannot be reassigned to an object. Python being a dynamically typed language, earlier was short of this feature. But from the 3.8 version of Python, we do have a feature named “Final” from the typing module. However, we will also look into other tools present in Python, that will help us achieve a complete concept of immutability.
The ‘Final’ keyword, introduced in version 3.8, serves as an equivalent to Java’s final keyword, offering a way to declare variables and methods immutable. While it does not enforce immutability at runtime, it signals to type checkers like Mypy that certain elements should not be modified. This article explores Python’s approach to immutability, including alternatives like tuples and frozen sets, offering insights into achieving data constancy similar to Java’s final keyword.
Also Read: What is The Python Equivalent of ~/.bashrc?
Understanding the ‘final’ Keyword in Java
In Java, the ‘final’ keyword serves the following purposes:
Final Keyword in Java: Variables and Constants
Java allows users to declare variables and attributes as final. Once declared and assigned, they cannot be modified ahead in the program.
Java’s Final Keyword: Methods and Attributes in Sub-Classes
Java allows us to declare methods and attributes of classes as Final. When classes are inherited, Java doesn’t allow subclasses to override existing final methods of the parent class. Thus it is one of the properties of the final keyword to stop users from redefining methods declared as final.
Final Classes Cannot be Inherited
Similarly, final classes cannot be inherited by other classes in Java. The functions and attributes inside final classes are also final. Java also prevents extending such classes via interfaces.
Python’s Final Keyword Equivalent
From Python 3.8, the Final keyword was introduced in the ‘typing’ module of Mypy. Mypy is an optional type checker that is used to type-check the Python program.
Mypy and the ‘Final’ Typing in Python: To run the typing module, one should install Mypy using pip in their systems. Head over to references for more details.
Now, we look at some of the properties exhibited by the Final keyword.
Demonstrating Final Constants and Variables in Python
Likewise, Java, and Python allow users to declare variables and constants as Final. Once declared, they cannot be redefined, reassigned or overridden. This prevents modification at modular and class levels.
For example:
from typing import Final
# Variable declared as Final
MAX: Final = 9000
MAX = 1
class A:
# Attribute declared as Final
TIMEOUT: Final[int] = 10
class B(A):
TIMEOUT = 1

Here we have two cases:
- Variable declared as Final: The variable MAX is declared Final, which prevents us from assigning a new value in the third line.
- Attribute defined as Final: Inside class A, an attribute “TIMEOUT” is defined as Final. After the class B inherits class A, the attribute “TIMEOUT” is also inherited as a property. But as it was declared Final, Python doesn’t allow us to assign a new value to the attribute.
Illustrating Final Methods in Python
Similarly, Mypy allows users to declare class functions, static functions, and instance functions as Final.
from typing import final
class Parent:
@final
def method(self) -> None:
class Chlid(Base):
def method(self) -> None: # Error: cannot override a final method

In this example, the child class tries to override the Final method in the parent class. Thus Python states a compilation error because the final methods cannot be redefined.
Understanding Final Classes in Python
Mypy allows one to make classes as final. It simply reflects that the classes cannot be subclassed.
from typing import final
@final
class Leaf:
class MyLeaf(Leaf): # Error: Leaf can't be subclassed

Here the catch is that decorator @final is used to inform Mypy about a class that should not be inherited. But it cannot prevent subclassing during runtime.
Exploring Alternatives to Mypy for Immutability
Rather than fussing over libraries, one can use immutable data structures to obtain a similar behavior.
Immutability with Tuples in Python
In Python, tuples are immutable sequences. By using tuples, we can create variables that cannot be modified once defined.
For Example:
# Creating an Immutable Tuple
my_tuple = (1, 2, 3, "immutable", 5.5)
my_tuple[0] = 10

The example shows that once a tuple is created, its elements cannot be altered, making it an immutable data structure in Python. Hence operations like item assignment, remove, update and add are not present in Tuples because they cannot be modified, once declared.
Named Tuples: A Pythonic Way to Immutable Objects
NamedTuples provide a readable and convenient way to define immutable classes.
For Example:
from collections import namedtuple
# Creating an Immutable Namedtuple
Person = namedtuple("Person", ["name", "age", "city"])
# Creating an instance of the named tuple
person_info = Person(name="Alice", age=30, city="Wonderland")
person_info.name = "Bob"

Thus here we create a NamedTuple named as Person. During declaration of Person, we name the properties (name, age and city). Secondly we create an instance of the class, by providing the values to the attributes. Lastly, Python prevents us from modifying the instance’s attributes.
Frozen Sets for Python Immutability
Frozen Sets are immutable Set Objects that cannot have duplicate values.
For Example:
# Creating an Immutable Frozenset
original_set = {1, 2, 3, 4, 5}
# Creating a frozenset from the original set
immutable_set = frozenset(original_set)
immutable_set.add(6)

Here the Attribute Error states that frozenset object do not have attribute like add because they are immutable. Hence operations like remove, update and add are not present in Frozen Set because they cannot be modified, once declared.
Custom Classes for Immutability in Python
Creating custom classes with read-only properties can also achieve immutability.
For Example:
class ImmutablePerson:
def __init__(self, name):
self._name = name
@property
def name(self):
return self._name
# Creating an instance of Immutable Person
person = ImmutablePerson(name="Alice")
# Attempting to modify the attributes directly would result in an error
person.name = "Bob"

In this example, when the attribute “name” of an instance person is changed, Python shows an Attribute Error. This is because “@property” is used to mark function “name” as read-only, which makes it immutable.
Also Read: Oop – Python Equivalent of Java’s Compareto()
Rules to Remember When Using Python’s Final
- When using Final from Mypy, keep the following things in mind:
- Do not forget to install Mypy before starting your code.
- At most one final declaration can be made at modular or class level for an attribute. There can not be a class level as well as instance level final declarations together.
- When declaring an attribute as final, do assign a value to it. There can be one assignment to a particular final attribute.
- Do not use final with arguments of a function.
- Declaring a name as final guarantees that a particular value cannot be modified. But it doesn’t state that it is immutable. Therefore it is similar to the concept of immutability , but not same!
Example: If we define an array as final , we can still append values to it. But cannot modify the existing values at initialized indices.
- In order to achieve complete immutability , use data-structures like Tuples, NamedTuples, Frozen Sets and Custom Classes.
Is there an exact equivalent to Java’s ‘final’ keyword in Python?
In Python, the closest equivalent to Java’s ‘final’ keyword is the typing.Final annotation introduced in Python 3.8 with the Mypy library. While typing.Final mirrors aspects of Java’s ‘final’, like restricting reassignment, it falls short of complete immutability. Therefore, Python developers often use other constructs like tuples, named tuples, frozen sets, and custom classes to achieve true immutability in their code.
How does typing.Final in Python differ from true immutability?
While typing.Final in Python prevents the reassignment of a variable, it doesn’t make the variable’s value truly immutable. A typing.Final variable guarantees that its reference won’t change, but the underlying data can still be mutable. For instance, a list declared as Final can’t be reassigned, but items within the list can still be modified, added, or removed. This characteristic differentiates it from complete immutability seen in languages like Java.
What’s the best way to achieve immutability in Python?
The optimal approach to achieve immutability in Python varies based on the specific requirements of your application. If type-checking and preventing reassignment are your primary concerns, use typing.Final from Mypy is a good choice. However, for complete immutability—where data structures cannot be altered after creation—relying on Python’s built-in immutable data types like tuples and frozen sets, or designing custom classes with read-only properties, is more effective.
Conclusion
As we’ve seen, Python’s approach to immutability, although different from Java’s final keyword, offers powerful alternatives. From the ‘Final’ keyword in Mypy to immutable data structures like tuples and frozen sets, Python provides a range of options to prevent data modification. Which approach will you choose for your next Python project?
References