Review of special class methods in Python: the use of magical methods to configure object behavior.

онлайн тренажер по питону
Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

A self-study guide for Python 3 compiled from the materials on this site. Primarily intended for those who want to learn the Python programming language from scratch.

Special class methods in Python: a complete guide

Special class methods, also known as magic methods or dander methods (from the English double underscore "__"), are a powerful Python tool for customizing the behavior of user classes. These methods allow objects to interact with Python's built-in functions and operators, making the code more readable and pythonic.

What are Python special methods

Special methods are methods that Python calls automatically in certain situations. They provide special behavior for objects, allowing you to define custom actions for standard operations: object initialization, attribute access, comparison operations, arithmetic operations, and more.

Initialization and presentation methods

__init__(self, ...) class constructor

The initialization method is called when creating a new instance of the class. Used to initialize the attributes of an object:

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

person = Person("Anna", 25)
print(person.name ) # Conclusion: Anna

__str__(self) - string representation

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

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __str__(self):
return f"Dot({self.x}, {self.y})"

point = Point(3, 4)
print(str(point))  # Output: Point(3, 4)

__repr__(self) - formal representation

The method is called by the repr() function to get a formal string representation of the object. Must return a string that is a valid Python expression.:

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __repr__(self):
        return f"Point({self.x}, {self.y})"

    def __str__(self):
return f"Dot({self.x}, {self.y})"

point = Point(3, 4)
print(repr(point))  # Output: Point(3, 4)

Methods for working with size and content

__len__(self) object length

The method is called by the len() function to get the size of the object.:

class CustomList:
    def __init__(self, items):
        self.items = items

    def __len__(self):
        return len(self.items)

my_list = CustomList([1, 2, 3, 4, 5])
print(len(my_list))  # Output: 5

__contains__(self, item) verification of ownership

The method is called to check the content of an element in an object using the in operator:

class NumberSet:
    def __init__(self, numbers):
        self.numbers = set(numbers)

    def __contains__(self, item):
        return item in self.numbers

number_set = NumberSet([1, 2, 3, 4, 5])
print(3 in number_set) # Output: True
print(6 in number_set) # Output: False

Methods for comparing objects

__eq__(self, other) equality

A method for performing an equality comparison operation (==):

class Student:
    def __init__(self, name, student_id):
        self.name = name
        self.student_id = student_id

    def __eq__(self, other):
        if isinstance(other, Student):
            return self.student_id == other.student_id
        return False

student1 = Student("Ivan", 123)
student2 = Student("Peter", 123)
print(student1 == student2) # Output: True

Ordinal comparison methods

class Grade:
    def __init__(self, value):
        self.value = value

    def __lt__(self, other):
        return self.value < other.value

    def __le__(self, other):
        return self.value <= other.value

    def __gt__(self, other):
        return self.value > other.value

    def __ge__(self, other):
        return self.value >= other.value

    def __repr__(self):
        return f"Grade({self.value})"

grade1 = Grade(85)
grade2 = Grade(92)
print(grade1< grade2) # Output: True
print(grade1<= grade2) # Output: True
print(grade1> grade2) # Output: False
print(grade1>= grade2) # Output: False

Arithmetic operations

Basic arithmetic operators

class Vector:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __add__(self, other):
        return Vector(self.x + other.x, self.y + other.y)

    def __sub__(self, other):
        return Vector(self.x - other.x, self.y - other.y)

    def __mul__(self, other):
        if isinstance(other, (int, float)):
            return Vector(self.x * other, self.y * other)
        elif isinstance(other, Vector):
            return self.x * other.x + self.y * other.y # Scalar product

    def __truediv__(self, other):
        if isinstance(other, (int, float)):
            return Vector(self.x / other, self.y / other)
        raise TypeError("Division is possible only by a number")

    def __repr__(self):
        return f"Vector({self.x}, {self.y})"

# Usage examples
vector1 = Vector(2, 3)
vector2 = Vector(1, 4)

print(vector1 + vector2) # Output: Vector(3, 7)
print(vector1 - vector2) # Output: Vector(1, -1)
print(vector1 * 2) # Output: Vector(4, 6)
print(vector1 * vector2) # Output: 14
print(vector1 / 2) # Output: Vector(1.0, 1.5)

Methods for accessing elements

__getitem__(self, key) getting the element

class Matrix:
    def __init__(self, data):
        self.data = data

    def __getitem__(self, key):
        if isinstance(key, tuple):
            row, col = key
            return self.data[row][col]
        return self.data[key]

    def __setitem__(self, key, value):
        if isinstance(key, tuple):
            row, col = key
            self.data[row][col] = value
        else:
            self.data[key] = value

    def __delitem__(self, key):
        if isinstance(key, tuple):
            row, col = key
            del self.data[row][col]
        else:
            del self.data[key]

matrix = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print(matrix[0, 1]) # Output: 2
matrix[1, 2] = 10
print(matrix[1]) # Output: [4, 5, 10]

Methods for creating callable objects

__call__(self, *args, **kwargs)the called object

class Multiplier:
    def __init__(self, factor):
        self.factor = factor

    def __call__(self, value):
        return value * self.factor

double = Multiplier(2)
triple = Multiplier(3)

print(double(5)) # Output: 10
print(triple(4)) # Output: 12

Iterators and iteration methods

__iter__(self) and __next__(self) creating iterators

class Countdown:
    def __init__(self, start):
        self.start = start

    def __iter__(self):
        return self

    def __next__(self):
        if self.start <= 0:
            raise StopIteration
        self.start -= 1
        return self.start + 1

countdown = Countdown(5)
for num in countdown:
    print(num)
# Output: 5, 4, 3, 2, 1

# An alternative way is to return a ready-made iterator
class NumberList:
    def __init__(self, numbers):
        self.numbers = numbers

    def __iter__(self):
        return iter(self.numbers)

numbers = NumberList([1, 2, 3, 4, 5])
for num in numbers:
    print(num)

Context managers

__enter__(self) and __exit__(self, exc_type, exc_value, traceback)

class DatabaseConnection:
    def __init__(self, database_name):
        self.database_name = database_name
        self.connection = None

    def __enter__(self):
print(f"Database connection {self.database_name}")
self.connection = f"connection_to_{self.database_name}"
        return self.connection

    def __exit__(self, exc_type, exc_value, traceback):
        print(f"Closing connection with {self.database_name}")
if exc_type:
print(f"Error occurred: {exc_value}")
self.connection = None
        return False  # We do not suppress exceptions
with DatabaseConnection("mydb") as conn:
    print(f"Working with connection: {conn}")
# Output:
# Connecting to the mydb database
# Working with the connection: connection_to_mydb
# Closing the connection with mydb

Additional useful methods

__hash__(self) hashing objects

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __eq__(self, other):
        return isinstance(other, Point) and self.x == other.x and self.y == other.y

    def __hash__(self):
        return hash((self.x, self.y))

    def __repr__(self):
        return f"Point({self.x}, {self.y})"

# Now Point can be used in sets and as dictionary keys
points = {Point(1, 2), Point(3, 4), Point(1, 2)}
print(points) # Output: {Point(1, 2), Point(3, 4)}

__bool__(self) - logical value

class Account:
    def __init__(self, balance):
        self.balance = balance

    def __bool__(self):
        return self.balance > 0

    def __repr__(self):
        return f"Account({self.balance})"

account1 = Account(100)
account2 = Account(0)
account3 = Account(-50)

print(bool(account1))  # Output: True
print(bool(account2))  # Output: False
print(bool(account3)) # Output: False

if account1:
    print("There are funds in the account")

Practical tips for using

Recommendations for the effective use of special methods:

  1. Always implement __repr__ for debugging and development
  2. Implement __str__ for human-readable output
  3. When implementing __eq__, think about implementing __hash__
  4. Use isinstance()to check types in comparison methods
  5. Comparison methods should return NotImplemented for unsupported types
  6. In context managers, be sure to release resources in __exit__

Conclusion

Python's special methods provide a powerful way to integrate custom classes with the built-in functions and operators of the language. Using these methods correctly makes the code more readable, intuitive, and consistent with Python principles. Learning and applying magic methods is an important step in mastering object-oriented programming in Python.

 

categories

  • Introduction to Python
  • Python Programming Basics
  • Control Structures
  • Data Structures
  • Functions and Modules
  • Exception Handling
  • Working with Files and Streams
  • File System
  • Object-Oriented Programming (OOP)
  • Regular Expressions
  • Additional Topics
  • General Python Base