Basic Magic Methods

PythonPythonIntermediate
Practice Now

Introduction

In this tutorial, we will explore the basic magic methods in Python. Magic methods, also known as "dunder" methods (double underscore methods), allow you to define how Python objects behave in certain situations, enabling advanced and customized object manipulation.


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL python(("`Python`")) -.-> python/BasicConceptsGroup(["`Basic Concepts`"]) python(("`Python`")) -.-> python/FileHandlingGroup(["`File Handling`"]) python(("`Python`")) -.-> python/ControlFlowGroup(["`Control Flow`"]) python(("`Python`")) -.-> python/DataStructuresGroup(["`Data Structures`"]) python(("`Python`")) -.-> python/FunctionsGroup(["`Functions`"]) python(("`Python`")) -.-> python/ModulesandPackagesGroup(["`Modules and Packages`"]) python(("`Python`")) -.-> python/ObjectOrientedProgrammingGroup(["`Object-Oriented Programming`"]) python/BasicConceptsGroup -.-> python/comments("`Comments`") python/FileHandlingGroup -.-> python/with_statement("`Using with Statement`") python/BasicConceptsGroup -.-> python/variables_data_types("`Variables and Data Types`") python/BasicConceptsGroup -.-> python/numeric_types("`Numeric Types`") python/BasicConceptsGroup -.-> python/strings("`Strings`") python/BasicConceptsGroup -.-> python/booleans("`Booleans`") python/ControlFlowGroup -.-> python/conditional_statements("`Conditional Statements`") python/ControlFlowGroup -.-> python/for_loops("`For Loops`") python/DataStructuresGroup -.-> python/tuples("`Tuples`") python/DataStructuresGroup -.-> python/sets("`Sets`") python/FunctionsGroup -.-> python/function_definition("`Function Definition`") python/ModulesandPackagesGroup -.-> python/importing_modules("`Importing Modules`") python/ModulesandPackagesGroup -.-> python/using_packages("`Using Packages`") python/ModulesandPackagesGroup -.-> python/standard_libraries("`Common Standard Libraries`") python/ObjectOrientedProgrammingGroup -.-> python/classes_objects("`Classes and Objects`") python/ObjectOrientedProgrammingGroup -.-> python/constructor("`Constructor`") python/ObjectOrientedProgrammingGroup -.-> python/polymorphism("`Polymorphism`") python/ObjectOrientedProgrammingGroup -.-> python/encapsulation("`Encapsulation`") python/BasicConceptsGroup -.-> python/python_shell("`Python Shell`") python/FunctionsGroup -.-> python/build_in_functions("`Build-in Functions`") subgraph Lab Skills python/comments -.-> lab-7836{{"`Basic Magic Methods`"}} python/with_statement -.-> lab-7836{{"`Basic Magic Methods`"}} python/variables_data_types -.-> lab-7836{{"`Basic Magic Methods`"}} python/numeric_types -.-> lab-7836{{"`Basic Magic Methods`"}} python/strings -.-> lab-7836{{"`Basic Magic Methods`"}} python/booleans -.-> lab-7836{{"`Basic Magic Methods`"}} python/conditional_statements -.-> lab-7836{{"`Basic Magic Methods`"}} python/for_loops -.-> lab-7836{{"`Basic Magic Methods`"}} python/tuples -.-> lab-7836{{"`Basic Magic Methods`"}} python/sets -.-> lab-7836{{"`Basic Magic Methods`"}} python/function_definition -.-> lab-7836{{"`Basic Magic Methods`"}} python/importing_modules -.-> lab-7836{{"`Basic Magic Methods`"}} python/using_packages -.-> lab-7836{{"`Basic Magic Methods`"}} python/standard_libraries -.-> lab-7836{{"`Basic Magic Methods`"}} python/classes_objects -.-> lab-7836{{"`Basic Magic Methods`"}} python/constructor -.-> lab-7836{{"`Basic Magic Methods`"}} python/polymorphism -.-> lab-7836{{"`Basic Magic Methods`"}} python/encapsulation -.-> lab-7836{{"`Basic Magic Methods`"}} python/python_shell -.-> lab-7836{{"`Basic Magic Methods`"}} python/build_in_functions -.-> lab-7836{{"`Basic Magic Methods`"}} end

Object Initialization and Representation

In this section, we will explore object initialization and representation magic methods in Python. These methods allow you to define custom behavior for creating objects and representing them as human-readable and unambiguous strings.

__init__

The __init__ method is called when an object is created. It is used to initialize the object's attributes.

Let's start with a simple object. In person.py, create a class named Person that have two attributes.

class Person:
    def __init__(self, name: str, age: int):
        """
        Initialize the Person object with a name and age.

        :param name: The name of the person.
        :param age: The age of the person.
        """
        self.name = name
        self.age = age

__str__

The __str__ method is called by the str() built-in function and the print() function to get a human-readable string representation of the object.

    ## ... (previous code in person.py)

    def __str__(self) -> str:
        """
        Return a human-readable string representation of the Person object.

        :return: A string describing the person.
        """
        return f"{self.name} is {self.age} years old."

__repr__

The __repr__ method is called by the repr() built-in function and used in the interactive interpreter to get a string representation that, if possible, can be used to recreate the object.

    ## ... (previous code in person.py)

    def __repr__(self) -> str:
        """
        Return a string representation of the Person object that can be used to recreate the object.

        :return: A string in the format 'Person(name, age)'.
        """
        return f"Person('{self.name}', {self.age})"

Example: Using the Basic Magic Methods

Now that we have defined the basic magic methods for our Person class, let's see how they work in init_repr_example.py:

from person import Person

## Create a new Person object
p = Person("Alice", 30)

## Use the __str__ method with the print function
print(p)  ## Output: Alice is 30 years old.

## Use the __repr__ method in the interactive interpreter
print(repr(p))  ## Output: Person('Alice', 30)

Then typing the following command in the terminal to execute the script.

python init_repr_example.py

Object Comparison

In this section, we will explore the magic methods used for object comparison in Python. These methods allow you to define custom comparison logic for objects of your class.

__eq__

The __eq__ method is used to determine if two objects are equal. It is called by the == operator.

    ## ... (previous code in person.py)

    def __eq__(self, other: "Person") -> bool:
        """
        Compare two Person objects for equality.

        :param other: The other Person object to compare with.
        :return: True if both objects have the same name and age, False otherwise.
        """
        if isinstance(other, Person):
            return self.name == other.name and self.age == other.age
        return False

__ne__

The __ne__ method is used to determine if two objects are not equal. It is called by the != operator.

    ## ... (previous code in person.py)

    def __ne__(self, other: "Person") -> bool:
        """
        Compare two Person objects for inequality.

        :param other: The other Person object to compare with.
        :return: True if the objects have different names or ages, False otherwise.
        """
        return not self.__eq__(other)

__lt__

The __lt__ method is used to determine if one object is less than another. It is called by the < operator.

    ## ... (previous code in person.py)

    def __lt__(self, other: "Person") -> bool:
        """
        Compare two Person objects to see if one is less than the other based on age.

        :param other: The other Person object to compare with.
        :return: True if the current object's age is less than the other object's age, False otherwise.
        """
        if isinstance(other, Person):
            return self.age < other.age
        return NotImplemented

__le__

The __le__ method is used to determine if one object is less than or equal to another. It is called by the <= operator.

    ## ... (previous code in person.py)

    def __le__(self, other: "Person") -> bool:
        """
        Compare two Person objects to see if one is less than or equal to the other based on age.

        :param other: The other Person object to compare with.
        :return: True if the current object's age is less than or equal to the other object's age, False otherwise.
        """
        if isinstance(other, Person):
            return self.age <= other.age
        return NotImplemented

__gt__

The __gt__ method is used to determine if one object is greater than another. It is called by the > operator.

    ## ... (previous code in person.py)

    def __gt__(self, other: "Person") -> bool:
        """
        Compare two Person objects to see if one is greater than the other based on age.

        :param other: The other Person object to compare with.
        :return: True if the current object's age is greater than the other object's age, False otherwise.
        """
        if isinstance(other, Person):
            return self.age > other.age
        return NotImplemented

__ge__

The __ge__ method is used to determine if one object is greater than or equal to another. It is called by the >= operator.

    ## ... (previous code in person.py)

    def __ge__(self, other: "Person") -> bool:
        """
        Compare two Person objects to see if one is greater than or equal to the other based on age.

        :param other: The other Person object to compare with.
        :return: True if the current object's age is greater than or equal to the other object's age, False otherwise.
        """
        if isinstance(other, Person):
            return self.age >= other.age
        return NotImplemented

Example: Using the Object Comparison Magic Methods

Now that we have defined the object comparison magic methods for our Person class, let's see how they work in compare_example.py:

from person import Person

## Create two Person objects
p1 = Person("Alice", 30)
p2 = Person("Bob", 35)

## Use the __eq__ and __ne__ methods
print(p1 == p2)  ## Output: False
print(p1 != p2)  ## Output: True

## Use the __lt__, __le__, __gt__, and __ge__ methods
print(p1 < p2)  ## Output: True
print(p1 <= p2)  ## Output: True
print(p1 > p2)  ## Output: False
print(p1 >= p2)  ## Output: False

Then typing the following command in the terminal to execute the script.

python compare_example.py

Object Destruction

In this section, we will explore the object destruction magic method in Python. The method allows you to define custom behavior when an object is about to be destroyed.

__del__

The __del__ method is called when an object is about to be destroyed. It allows you to perform clean-up tasks, such as closing file handles or releasing resources, before the object is garbage collected.

    ## ... (previous code in person.py)

    def __del__(self):
        """
        Clean up the Person object before it is destroyed.
        """
        print(f"Person '{self.name}' is being deleted.")

Example: Using the Object Destruction Magic Method

Now that we have defined the object destruction magic method for our Person class, let's see how it works in del_example.py:

from person import Person

## Create a Person object and then delete it
p = Person("Alice", 30)
del p  ## Output: Person 'Alice' is being deleted.

Then typing the following command in the terminal to execute the script.

python del_example.py

It's important to note that the __del__ method is not guaranteed to be called immediately when an object is no longer needed. The actual deletion of the object depends on the Python interpreter's garbage collection mechanism. The __del__ method is called when the garbage collector decides to remove the object from memory.

Summary

In this series of tutorials, we explored Python's magic methods, also known as "dunder" methods (double underscore methods), which allow you to define custom behaviors for your objects in various situations.

By mastering these magic methods, you can create more powerful and customizable Python classes and objects. Understanding and implementing these methods will enable you to write more efficient, clean, and Pythonic code, making your programs more robust and maintainable.

Other Python Tutorials you may like