[ Web Proxy ]
URL:
Viewing: https://python-course.eu/oop/creating-immutable-classes-in-python.php [Back]  [Original]

4. Creating Immutable Classes In Python | OOP | python-course.eu
python-course.eu
Search site:

Live Python classes by highly experienced instructors:

instructor-led training course [instructor-led training course]
Instructor-led training courses by Bernd Klein

  1. Intro to Object Oriented Programming
  2. Object Oriented Programming
  3. Class vs. Instance Attributes
  4. Properties vs. Getters and Setters
  5. Creating Immutable Classes In Python
  6. Dataclasses In Python
  7. Implementing a Custom Property Class
  8. Magic Methods
  9. Dynamic Data Transformation
  10. Introduction to Descriptors
  11. Inheritance
  12. Multiple Inheritance
  13. Multiple Inheritance: Example
  14. Callable Instances of Classes
  15. Slots: Avoiding Dynamically Created Attributes
  16. Polynomial Class
  17. Dynamically Creating Classes with type
  18. Road to Metaclasses
  19. Metaclasses
  20. Count Function calls with the help of a Metaclass
  21. The 'ABC' of Abstract Base Classes
  22. OOP Purely Functional

This website contains a free and extensive online tutorial by Bernd Klein, using material from his classroom Python training courses.

If you are interested in an instructor-led classroom training course, have a look at these Python classes:

instructor-led training course [instructor-led training course]
Instructor-led training course by Bernd Klein at Bodenseo

Image kabliczech - Fotolia.com

This page was written by Bernd Klein.

Bernd is an experienced computer scientist with a history of working in the education management industry and is skilled in Python, Perl, Computer Science, and C++. He has a Dipl.-Informatiker / Master Degree focused in Computer Science from Saarland University.

PDF versions of this site [PDF versions of this site]

PDF logo [PDF logo] PDF version of this site

This website is free of annoying ads. We want to keep it like this. You can help with your donation:

[Go]

The need for donations

4. Creating Immutable Classes In Python

By Bernd Klein. Last modified: 19 Feb 2024.

Why do we need immutable classes?

Motionless pantomine as a symbol for immutable classes [Motionless pantomine as a symbol for immutable classes]

Popular examples of immutable classes in Python include integers, floats, strings and tuples. Many functional programming languages, such as Haskell or Scala, heavily rely on immutability as a fundamental concept in their design. The reason is that immutable classes offer several advantages in software development:

  1. Thread Safety: Immutable objects are inherently thread-safe. Since their state cannot be changed after creation, multiple threads can access them concurrently without the need for locks or synchronization. This can simplify concurrent programming and reduce the risk of race conditions.

  2. Predictable Behavior: Once an immutable object is created, its state remains constant throughout its lifetime. This predictability makes it easier to reason about the behavior of the object, leading to more robust and maintainable code.

  3. Cacheability: Immutable objects can be safely cached, as their values never change. This is particularly beneficial for performance, as it allows for efficient memoization and caching strategies.

  4. Simplifies Testing: Since the state of an immutable object doesn't change, testing becomes simpler. You don't need to consider different states or mutation scenarios, making it easier to write tests and verify the correctness of your code.

  5. Consistent Hashing: Immutable objects have consistent hash codes, which is essential for their use in data structures like dictionaries or sets. This ensures that objects with the same values produce the same hash code, simplifying their use in hash-based collections.

  6. Facilitates Debugging: Debugging can be easier with immutable objects because their state doesn't change. Once you identify the initial state of an object, it remains constant, making it easier to trace and understand the flow of your program.

  7. Promotes Functional Programming: Immutable objects align well with the principles of functional programming. In functional programming, functions and data are treated as separate entities, and immutability is a key concept. Immutable objects encourage a functional style of programming, leading to more modular and composable code.

  8. Prevents Unintended Changes: With mutable objects, unintended changes to the state may occur if references to the object are shared. Immutable objects eliminate this risk, as their state cannot be modified after creation.

Live Python training

instructor-led training course [instructor-led training course]

Enjoying this page? We offer live Python training courses covering the content of this site.

See our Python training courses

See our Machine Learning with Python training courses

Ways to Create Immutable Classes

Classes with Getters and no Setters

The following ImmutableRobot class implements private attributes __name and self.__brandname, which can only be read through the methods get_name and get_brandname but there is no way to change these attributes, at least no legal way:

class ImmutableRobot:
    
    def __init__(self, name, brandname):
        self.__name = name
        self.__brandname = brandname

    def get_name(self):
        return self.__name

    def get_brandname(self):
        return self.__brandname

robot = ImmutableRobot(name="RoboX", brandname="TechBot")
print(robot.get_name())      
print(robot.get_brandname()) 

OUTPUT:

RoboX
TechBot

We can rewrite the previous example by using properties and not suppling the setter methods. So logically the same as before:

class ImmutableRobot:
    def __init__(self, name, brandname):
        self.__name = name
        self.__brandname = brandname

    @property
    def name(self):
        return self.__name

    @property
    def brandname(self):
        return self.__brandname

robot = ImmutableRobot(name="RoboX", brandname="TechBot")
print(robot.name)       
print(robot.brandname) 


try:
    robot.name = "RoboY"
except AttributeError as e:
    print(e)  

try:
    robot.brandname = "NewTechBot"
except AttributeError as e:
    print(e) 

OUTPUT:

RoboX
TechBot
property 'name' of 'ImmutableRobot' object has no setter
property 'brandname' of 'ImmutableRobot' object has no setter

Using the dataclass Decorator

from dataclasses import dataclass

@dataclass(frozen=True)
class ImmutableRobot:
    name: str
    brandname: str

# Example usage:
robot = ImmutableRobot(name="RoboX", brandname="TechBot")
print(robot.name)
print(robot.brandname)

try:
    robot.name = "RoboY"
except AttributeError as e:
    print(e)

try:
    robot.brandname = "NewTechBot"
except AttributeError as e:
    print(e)

Using namedtuple from collections

Here's an alternative using namedtuple from the collections module:

from collections import namedtuple

ImmutableRobot = namedtuple('ImmutableRobot', ['name', 'brandname'])

# Example usage:
robot = ImmutableRobot(name="RoboX", brandname="TechBot")
print(robot.name)
print(robot.brandname)

# Attempting to modify attributes will raise an AttributeError
try:
    robot.name = "RoboY"
except AttributeError as e:
    print(e)

try:
    robot.brandname = "NewTechBot"
except AttributeError as e:
    print(e)

OUTPUT:

RoboX
TechBot
can't set attribute
can't set attribute

In this example, namedtuple creates a simple class with named fields, and instances of this class are immutable. Just like with dataclass, attempting to modify attributes will result in an AttributeError.

Both namedtuple and dataclass provide a concise way to create immutable classes in Python. The choice between them depends on your specific needs and preferences. namedtuple is more lightweight, while dataclass offers additional features and customization options.

__slots__

Slots have nothing to do with creating an immutable class. Yet, it can be mistaken. With the aid of __slots__ we set the number of attributes to a fixed set. In other words: The __slots__ attribute in Python is used to explicitly declare data members (attributes) in a class. It restricts the creation of new attributes in instances of the class, allowing only the attributes specified in __slots__ to be defined. The attributes themselves can change of course, so the class can be mutable, but cannot dynamically extended with additional attributes. Though the main benefit of __slots__ is the fact that we can significantly reduce the memory overhead associated with each instance of the class. Traditional classes store attributes in a dynamic dictionary, which consumes extra memory. With __slots__, attribute names are stored in a tuple, and the instance directly allocates memory for these attributes.

Yet, when we use dataclass(frozen=True) no new attributes can be dynamically added:

class ImmutableRobot:
    __slots__ = ('__name', '__brandname')

    def __init__(self, name, brandname):
        self.__name = name
        self.__brandname = brandname

    @property
    def name(self):
        return self.__name

    @property
    def brandname(self):
        return self.__brandname

robot = ImmutableRobot(name="RoboX", brandname="TechBot")
print(robot.name)       
print(robot.brandname) 

By using __slots__, you explicitly declare the attributes that instances of the class will have, which can help reduce memory usage and improve performance, especially when creating a large number of instances.

Live Python training

instructor-led training course [instructor-led training course]

Enjoying this page? We offer live Python training courses covering the content of this site.

Upcoming online Courses

See our Python training courses

See our Machine Learning with Python training courses

top


Web Proxy Viewer  |  New URL  |  Original Page