Перегрузка операторов в Python
Как мы знаем, оператор + может выполнять сложение двух чисел, объединять два списка или конкатенировать две строки.
С некоторыми изменениями мы можем использовать оператор + для работы и с пользовательскими объектами. Эта возможность в Python, которая позволяет одному и тому же оператору иметь разные значения в зависимости от контекста, называется перегрузкой операторов.
Специальные функции в Python
В Python методы, которые имеют два подчёркивания __ до и после своих имён, имеют особое значение. Например, __add__(), __len__() и т.д.
Эти специальные методы могут использоваться для реализации определённых функций или поведения.
Давайте используем метод __add__() для сложения двух чисел вместо использования оператора +.
number1 = 5
# similar to number2 = number1 + 6
number2 = number1.__add__(6)
print(number2) # 11
Возможно использовать метод __add__() для целых чисел, потому что:
Всё в Python — это объект, включая целые числа.
У целых чисел определён метод
__add__(), который мы можем использовать.
На самом деле оператор + внутренне вызывает метод __add__() для сложения целых чисел и чисел с плавающей точкой.
Вот некоторые из специальных функций, доступных в Python:
Функция |
Описание |
|---|---|
|
Инициализирует атрибуты объекта. |
|
Возвращает строковое представление объекта. |
|
Возвращает длину объекта. |
|
Складывает два объекта. |
|
Вызывает объекты класса как обычную функцию. |
Как использовать перегрузку операторов?
Предположим, мы хотим использовать оператор + для сложения двух пользовательских объектов.
Поскольку оператор + внутренне вызывает метод __add__(), если мы реализуем этот метод в классе, мы можем заставить объекты этого класса работать с оператором +.
Пример: Сложение двух координат (без перегрузки)
Сначала давайте напишем программу для сложения двух координат (без использования перегрузки оператора +).
class Point:
def __init__(self, x = 0, y = 0):
self.x = x
self.y = y
def add_points(self, other):
x = self.x + other.x
y = self.y + other.y
return Point(x, y)
p1 = Point(1, 2)
p2 = Point(2, 3)
p3 = p1.add_points(p2)
print((p3.x, p3.y)) # Output: (3, 5)
В приведённом выше примере мы создали метод add_points() для сложения двух точек. Для вызова этого метода мы использовали p1.add_points(p2).
Давайте напишем тот же код, используя оператор + для сложения двух точек.
Пример: Сложение двух координат (с перегрузкой)
class Point:
def __init__(self, x = 0, y = 0):
self.x = x
self.y = y
def __add__(self, other):
x = self.x + other.x
y = self.y + other.y
return Point(x, y)
p1 = Point(1, 2)
p2 = Point(2, 3)
# this statment calls the __add__() method
p3 = p1 + p2
print((p3.x, p3.y)) # Output: (3, 5)
Здесь этот код p1 + p2 вызывает метод __add__(self, other). Параметр self принимает p1, а параметр other принимает p2 в качестве аргументов.
Не злоупотребляйте операторами
В приведённой программе мы могли бы легко использовать оператор + для вычитания следующим образом:
def __add__(self, other):
x = self.x - other.x
y = self.y - other.y
return Point(x, y)
Теперь оператор + в приведённом коде выполняет вычитание точек. Хотя программа работает без ошибок, вам следует абсолютно избегать этого. Мы всегда должны использовать операторы соответствующим образом при их перегрузке.
Аналогично, мы можем перегрузить и другие операторы. Специальные функции, которые нам нужно реализовать, приведены в таблице ниже.
Оператор |
Выражение |
Внутренне |
|---|---|---|
Сложение |
|
|
Вычитание |
|
|
Умножение |
|
|
Степень |
|
|
Деление |
|
|
Целочисленное деление |
|
|
Остаток (по модулю) |
|
|
Побитовый сдвиг влево |
|
|
Побитовый сдвиг вправо |
|
|
Побитовое AND |
|
|
Побитовое OR |
|
|
Побитовое XOR |
|
|
Побитовое NOT |
|
|
Перегрузка операторов сравнения
Python не ограничивает перегрузку операторов арифметическими операторами. Мы также можем перегружать операторы сравнения.
Вот пример того, как мы можем перегрузить оператор < для сравнения двух объектов класса Person на основе их age:
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
# overload < operator
def __lt__(self, other):
return self.age < other.age
p1 = Person("Alice", 20)
p2 = Person("Bob", 30)
print(p1 < p2) # prints True
print(p2 < p1) # prints False
Вывод
True
False
Здесь __lt__() перегружает оператор < для сравнения атрибута age двух объектов.
Метод __lt__() возвращает:
True— если возраст первого объекта меньше возраста второго объектаFalse— если возраст первого объекта больше возраста второго объекта
Аналогично, специальные функции, которые нам нужно реализовать для перегрузки других операторов сравнения, приведены в таблице ниже.
Оператор |
Выражение |
Внутренне |
|---|---|---|
Меньше чем |
|
|
Меньше или равно |
|
|
Равно |
|
|
Не равно |
|
|
Больше чем |
|
|
Больше или равно |
|
|
Преимущества перегрузки операторов
Вот некоторые преимущества перегрузки операторов:
Улучшает читаемость кода, позволяя использовать знакомые операторы.
Гарантирует, что объекты класса ведут себя согласованно со встроенными типами и другими пользовательскими типами.
Упрощает написание кода, особенно для сложных типов данных.
Позволяет повторно использовать код, реализуя один метод оператора и используя его для других операторов.
Смотрите также: