Магические методы __getitem__, __setitem__ и __delitem__

В Python магические методы позволяют вам определять специальное поведение для экземпляров вашего класса. Одними из наиболее полезных являются методы, которые отвечают за доступ, изменение и удаление элементов по индексу или ключу: __getitem__, __setitem__ и __delitem__. Эти методы дают возможность экземплярам вашего класса вести себя подобно спискам, словарям и другим стандартным коллекциям Python.

Метод __getitem__

Метод __getitem__ отвечает за доступ к элементам экземпляра класса по индексу или ключу. По умолчанию, если у объекта нет этого метода, попытка обращения по индексу приводит к ошибке TypeError: 'Object' object is not subscriptable. Это значит, что объект не поддерживает операцию индексирования, как это делают списки и словари.

Допустим, мы создаем класс Matrix, который содержит двумерный массив значений. Мы хотим обращаться к элементам матрицы по индексу, например, matrix[1][2], но без __getitem__ это невозможно:

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

matrix = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print(matrix[1][2])  # Ошибка TypeError

Для того чтобы этот код работал, нужно определить метод __getitem__:

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

    def __getitem__(self, index):
        if isinstance(index, int) and 0 <= index < len(self.values):
            return self.values[index]
        else:
            raise IndexError("Индекс вне границ матрицы")

matrix = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print(matrix[1][2])  # Вывод: 6

В данном примере __getitem__ проверяет, что индекс в пределах допустимого диапазона, а затем возвращает нужную строку матрицы. Если передать недопустимый индекс, то возбуждается исключение IndexError.

Теперь добавим поддержку обращения к элементам матрицы по строковому ключу: если передается строка, мы будем использовать ее длину как индекс:

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

    def __getitem__(self, index):
        if isinstance(index, int) and 0 <= index < len(self.values):
            return self.values[index]
        elif isinstance(index, str):
            index = len(index)
            if 0 <= index < len(self.values):
                return self.values[index]
            else:
                raise IndexError("Индекс вне границ матрицы")
        else:
            raise TypeError("Недопустимый тип индекса")

matrix = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print(matrix["abc"])  # Вывод: [4, 5, 6] (длина строки "abc" равна 3)


Метод __setitem__

Метод __setitem__ позволяет изменять значения в объекте по индексу или ключу. Он вызывается при присваивании значения с помощью синтаксиса obj[index] = value. Рассмотрим, как можно изменить значения элементов в матрице:

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

    def __getitem__(self, index):
        return self.values[index]

    def __setitem__(self, index, value):
        if isinstance(index, int) and 0 <= index < len(self.values):
            self.values[index] = value
        elif isinstance(index, str):
            index = len(index)
            if 0 <= index < len(self.values):
                self.values[index] = value
            else:
                raise IndexError("Индекс вне границ матрицы")
        else:
            raise TypeError("Недопустимый тип индекса")

matrix = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
matrix[1] = [10, 11, 12]
matrix["four"] = [13, 14, 15]
print(matrix.values)  # Вывод: [[1, 2, 3], [10, 11, 12], [13, 14, 15]]


Метод __delitem__

Метод __delitem__ позволяет удалять элементы по индексу или ключу. Он вызывается при использовании оператора del obj[index]. По умолчанию, метод удаляет элемент по указанному индексу. Однако мы можем модифицировать его так, чтобы удалялись все элементы, равные переданному значению:

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

    def __getitem__(self, index):
        return self.values[index]

    def __setitem__(self, index, value):
        self.values[index] = value

    def __delitem__(self, key):
        if isinstance(key, int):
            del self.values[key]
        elif isinstance(key, list):
            for value in key:
                while value in self.values:
                    self.values.remove(value)
        else:
            raise TypeError("Неверный тип ключа")

matrix = Matrix([3, 4, 4, 5, 6, 4])
del matrix[4]  # Удаляет элемент с индексом 4
print(matrix.values)  # Вывод: [3, 4, 4, 5, 4]

del matrix[[4, 5]]  # Удаляет все четверки и пятерки
print(matrix.values)  # Вывод: [3]

В этом примере __delitem__ может принимать список значений и удаляет все вхождения элементов, указанных в этом списке. Это позволяет выполнять более сложные операции удаления.


Вот таблица по лекции о методах __getitem__, __setitem__, и __delitem__:

ТемаОписание
Метод __getitem__Отвечает за доступ к элементам объекта по индексу или ключу. Если метод не реализован, объект не поддерживает индексирование (TypeError).
Пример использованияВ классе Matrix метод __getitem__ позволяет обращаться к элементам матрицы по индексу, как в списке: matrix[1][2].
Поддержка строковых ключейМетод может обрабатывать строковые индексы, где длина строки используется в качестве индекса: matrix["abc"] (длина строки "abc" равна 3).
Метод __setitem__Позволяет изменять значения элементов по индексу или ключу с помощью синтаксиса obj[index] = value.
Пример изменения значенийВ классе Matrix можно менять значения как по целочисленным, так и по строковым индексам: matrix[1] = [10, 11, 12], matrix["four"] = [13, 14, 15].
Метод __delitem__Удаляет элементы по индексу или ключу. Вызывается при использовании оператора del obj[index].
Пример удаления элементовВ классе Matrix метод может удалять элементы по индексу (del matrix[4]) или по списку значений (del matrix[[4, 5]], удаляются все четверки и пятерки).
ИтогМетоды __getitem__, __setitem__, и __delitem__ позволяют кастомным классам работать с элементами как стандартные коллекции, упрощая доступ, изменение и удаление.

Таблица охватывает основные моменты лекции и примеры использования этих магических методов в Python.


Итог:

Магические методы __getitem__, __setitem__ и __delitem__ дают гибкость для работы с кастомными классами, позволяя им вести себя как стандартные коллекции. Это упрощает доступ к элементам, их изменение и удаление, а также предоставляет возможности для сложных логических операций.

Попробуйте самостоятельно реализовать аналогичные методы для других структур данных, чтобы лучше понять их применение!

Перейти к следующему шагу

Комментарии