Перегрузка операторов в классах. Общие сведения. Методы, перегружающие операторы. Примеры
Содержание
- 1. Общие сведения о перегрузке операторов
- 2. Принципы, лежащие в основе перегрузки операторов в классах
- 3. Перечень методов, которые можно перегружать
- 4. Перегрузка конструктора класса. Пример
- 5. Перегрузка оператора + для класса Point (точка). Пример
- Связанные темы
Поиск на других ресурсах:
1. Общие сведения о перегрузке операторов
В языке программирования Python, классы (в отличие от модулей) могут переопределять операторы. Такой механизм называется перегрузкой операторов. Перегрузка оператора в классе — это сопоставление оператору языка Python (например, оператору +, –, * и т.д.) соответствующего метода с целью вызова кода этого метода при использовании перегруженного оператора. Иными словами, перегрузка операторов позволяет использовать объекты классов в качестве операндов в выражениях или других встроенных операциях, таких как сложение, умножение, получение среза, вывод и т.д.
Если в программе, для некоторого объекта класса, вызывается перегруженный оператор, то автоматически вызывается метод, который реализуюет действия этого оператора. Таким образом, при перегрузке оператора + (сложение), в реализующем его методе можно запрограммировать любые действия, даже вычитание, умножение или что угодно. Однако логики, такой код иметь не будет, вводя в заблуждение самого программиста. Привычным делом, метод, соответствующий оператору +, должен что-то суммировать.
Использование механизма перегрузки операторов в классах дает следующие преимущества:
- объекты классов теснее интегрируются в объектную модель языка Python;
- объекты классов действуют более естественно, так же как встроенные объекты языка;
- появляется возможность использовать объекты классов в сочетании со встроенными типами;
- программный код имеет тенденцию к лучшему восприятию.
Перегрузка операторов в классах имеет целью создание удобных инструментальных средств для других программистов, использующих эти классы в своих проектах.
⇑
2. Принципы, лежащие в основе перегрузки операторов в классах
В основе механизма перегрузки операторов лежат следующие принципы:
- при использовании перегрузки операторов в классе, используются методы, начинающиеся и заканчивающиеся двумя символами подчеркивания (например __add__(), __str__() и другие). Эти методы имеют специальное назначение и строго определенные (фиксированные) имена для каждой операции;
- как только вызывается встроенный оператор (операция), то вызов соответствующего метода происходит автоматически. Например, при указании переопределенного оператора + для объекта класса, будет автоматически вызываться метод __add __(). Этот метод обязательно должен быть реализован в классе;
- если нужно получить результат операции для объекта класса, то в методе класса этот результат возвращается оператором return;
- в классах может быть переопределено большинство вложенных операторов языка Python. Каждому оператору соответствует имя метода, который реализует перегрузку;
- если в классе не реализовано переопределение некоторого оператора, то это означает, что экземпляр (объект) этого класса не поддерживает эти операции. Например, если в классе не реализован метод __sub__(), то объект этого класса не поддерживает операцию вычитания (X-Y);
- переопределение в классе операторов не является обязательной функциональной особенностью. Иными словами, класс не обязательно должен содержать методы переопределения операторов;
- перегрузка операторов в классах позволяет интегрировать эти классы в объектную модель языка Python. Экземпляры классов лучше вписываются в интерфейс языка и действуют как встроенные типы.
⇑
3. Перечень методов, которые можно перегружать
Ниже приведен сокращенный перечень методов, которые перегружают различные операции. Методы группируются по следующим категориям:
- методы для всех видов операций;
- методы перегрузки операторов работы с коллекциями;
- методы для числовых операций в двоичной форме;
- методы для других операций над числами;
- методы для операций с дескрипторами;
- методы для операций, используемых с диспетчерами контекста.
⇑
3.1. Методы для всех видов операций
В этой категории определяются следующие методы:
- __new__(cls [, arg]*) – вызывается для создания и возврата нового экземпляра класса;
- __init__(self [, arg]*) – заменяет конструктор класса при создании экземпляра класса;
- __del__(self) – заменяет деструктор при сборке экземпляра класса в «мусор»;
- __repr__(self) – вызывается в операции repr(self);
- __str__(self) – вызывается в операции str(self) или print(self);
- __format__(self, format_specification) – вызывается встроенной функцией format();
- __bytes__(self) – вызывается функцией bytes() с целью возврата строкового представления типа bytes объекта self;
- __hash__(self) – вызывается при обработке хешированных коллекций;
- __bool__(self) – используется при проверке значения на истинность;
- __call__(self [, arg]*) – используется в операции self(args) при вызове экземпляра класса как функции;
- __getattr__(self, name) – вызывается по ссылке self.name, где name — символьная строка, обозначающая доступ к неопределенному атрибуту;
- __setattr__(self, name) – вызывается в операции self.name = value;
- __delattr__(self, name) – вызывается в операции del self.name;
- __lt__(self, other) – вызывается при проверке условия self<other;
- __le__(self, other) – вызывается при проверке условия self<=other;
- __eq__(self, other) – вызывается при проверке self==other;
- __ne__(self, other) – вызывается при проверке self!=other;
- __gt__(self, other) – вызывается при проверке self>other;
- __ge__(self, other) – вызывается при проверке self>=other;
- __slots__ – формирует дескриптор управления на уровне класса с резервированием места для объявляемых атрибутов в экземплярах классов;
- __instancecheck__(self, instance) – возвращает True для функции isinstance(), если экземпляр является прямым или неявным экземпляром класса;
- __subclasscheck__(self, subclass) – возвращает True для функции issubclass(), если подкласс должен считаться прямым или неявным подклассом данного класса;
- __dir__(self) – вызывается в операции dir(self) и возвращает последовательность имен атрибутов.
⇑
3.2. Методы перегрузки операторов работы с коллекциями
Перечень методов, используемых при переопределении операторов работы с коллекциями, последовательностями и отражениями:
- __len__(self) – вызывается в операции len() для получения размера коллекции;
- __contains__(self, item) – вызывается в операции item in self для проверки того, находится ли элемент item в коллекции self;
- __iter__(self) – вызывается в операции iter(self);
- __next__(self) – вызывается встроенной функцией next(self) в итерационном цикле;
- __getitem__(self, key) – вызывается в операциях self[key], self[i:j:k], x in self;
- __setitem__(self, key, value) – вызывается в операциях self[key] = value и self[i:j:k]=value;
- __delitem__(self, key) – вызывается в операциях del self[key] и del self[i:j:k];
- __reversed__(self) – вызывается встроенной функцией reversed() для реверсирования коллекции.
⇑
3.3. Методы для числовых операций в двоичной форме
Методы операций над двоичными числами делятся на подгруппы, которые описаны ниже.
3.3.1. Основные методы для операций над двоичными числами
К этой группе методов принадлежат:
- __add__(self, other) – вызывается в операторе суммирования self + other;
- __sub__(self, other) – вызывается в операторе вычитания self — other;
- __mul__(self, other) – вызывается в операторе умножения self * other;
- __truediv__(self, other) – вызывается в операторе деления self / other;
- __floordiv__(self, other) – вызывается в операторе self // other;
- __mod__(self, other) – вызывается в операторе self % other;
- __divmod__(self, other) – вызывается в операторе divmod(self, other);
- __pow__(self, other [, module]) – вызывается в операторе pow(self, other [, module]);
- __lshift__(self, other) – вызывается в операторе сдвига влево self << other;
- __rshift__(self, other) – вызывается в операторе сдвига вправо self >> other;
- __and__(self, other) – вызывается в операторе self & other;
- __xor__(self, other) – вызывается в операторе self ^ other;
- __or__(self, other) – вызывается в операторе self | other.
⇑
3.3.2. Методы для правосторонних операций над двоичными числами
В данной группе методов аргумент self размещается справа от операнда. Например, если в левосторонней операции умножения
self * other
происходит вызов
self.__mul__(other)
тогда, как в правосторонней операции умножения
other * self
происходит вызов
self.__rmul__(other)
Перечень правосторонних операций над двоичными числами следующий:
- __radd__(self, other) – аналог операции __add__(self, other) только правосторонний. Это значит, что аргумент self размещается в правой части оператора +: other + self;
- __rsub__(self, other) – вызывается в операторе вычитания other-self;
- __rmul__(self, other) – вызывается в операторе умножения other*self;
- __rtruediv__(self, other) – вызывается в операторе деления other/self;
- __rfloordiv__(self, other) – вызывается в операторе other//self;
- __rmod__(self, other) – вызывается в операторе other % self;
- __rdivmod__(self, other) – вызывается в операторе divmod(other, self);
- __rpow__(self, other [, module]) – вызывается в операторе pow(other, self [, module]);
- __rlshift__(self, other) – вызывается в операторе сдвига влево other << self;
- __rrshift__(self, other) – вызывается в операторе сдвига вправо other >> self;
- __rand__(self, other) – вызывается в операторе other & self;
- __rxor__(self, other) – вызывается в операторе other ^ self;
- __ror__(self, other) – вызывается в операторе other | self.
⇑
3.3.3. Комбинированные методы для операций над двоичными числами
Это методы, которые используются при перегрузке операций вроде +=, -=, >>= и других. Перечень этих методов следующий:
- __iadd__(self, other) – вызывается в операторе +=;
- __isub__(self, other) – вызывается в операторе -=;
- __imul__(self, other) – вызывается в операторе *=;
- __itruediv__(self, other) – вызывается в операторе деления /=;
- __ifloordiv__(self, other) – вызывается в операторе //=;
- __imod__(self, other) – вызывается в операторе %=;
- __ipow__(self, other [, modulo]) – вызов **=;
- __ilshift__(self, other) – вызывается в операторе <<=;
- __irshift__(self, other) – вызов >>=;
- __iand__(self, other) – вызов &=;
- __ixor__(self, other) – вызов ^=;
- __ior__(self, other) – вызов |=.
⇑
3.4. Методы для других операций над числами
К этой группе методов относятся следующие:
- __neg__(self) – вызывается в операции -self;
- __pos__(self) – вызывается в операции +self;
- __abs__(self) – вызывается в операции abs(self);
- __invert__(self) – вызов ~self;
- __complex__(self) – вызов в операции complex(self);
- __int__(self) – вызов в операции int(self);
- __float__(self) – вызов в операции float(self);
- __round__(self) – вызов round(self);
- __index__(self) – вызов index(self).
⇑
3.5. Методы для операций с дескрипторами
Эта группа методов применяется в случаях, когда атрибуту класса-владельца присваивается экземпляр класса (дескриптор), в котором эти методы определены. Перечень этих методов следующий:
- __get__(self, instance, owner) – вызывается для получения атрибута из класса-владельца (owner) или экземпляра данного класса (instance);
- __set__(self, instance, value) – вызывается для установления нового значения атрибута в экземпляре класса-владельца;
- __delete__(self, instance) – вызывается когда нужно удалить атрибут в экземпляре класса-владельца.
⇑
3.6. Методы для операций, используемых с диспетчерами контекста
К этим методам относятся методы, реализующие протокол диспетчера контекста. Этот протокол используется в операторе with. Перечень этих методов следующий:
- __enter__(self) – предназначен для входа в динамический контекст, связанный с данным объектом;
- __exit__(self) – реализует выход из динамического контекста связанного с данным объектом.
⇑
4. Перегрузка конструктора класса. Пример
Когда создается экземпляр из класса, тогда первым методом вызывается конструктор этого класса. В этот метод-конструктор целесообразно вписать код начальной инициализации данных класса, выделения необходимых ресурсов и тому подобное. Чтобы создать конструктор в классе, в этот класс должен быть включен метод __init __().
Примерный код класса, содержащий конструктор следующий
class ClassName: # конструктор, получающий некоторые параметры ... def __init__(self, ...): # инициализация в конструкторе ... ...
После такой реализации класса, можно создавать экземпляр класса вызовом
obj = ClassName(...) # здесь ... - список параметров конструктора
Пример. Объявляется класс Book, который описывает следующие данные о книге:
- author — имя автора книги;
- title — название книги;
- year — год издания;
- price — стоимость книги.
В классе Book объявляются следующие методы:
- метод __init __() — реализует конструктор класса, который получает 4 параметра;
- метод display() — выводит данные о книге в удобном виде;
- методы доступа к внутренним данным книги: getAuthor(), getTitle(), getYear(), getPrice().
После объявления класса демонстрируется создание экземпляра книги с помощью метода-конструктора.
# Перегрузка операторов в Python. # Перегрузка конструктора путем # реализации метода __init__() в классе class Book: # Метод-конструктор def __init__(self, author, title, year, price): self.author = author self.title = title self.year = year self.price = price # Метод, выводящий данные о книге def display(self): print("author = ", self.author, ", title = ", self.title, ", year = ", self.year, ", price = ", self.price) # Методы доступа к данным в классе def getAuthor(self): return self.author def getTitle(self): return self.title def getYear(self): return self.year def getPrice(): return self.price # 1. Создать объект класса Book, # вызывается метод-конструктор __init__() book1 = Book("Mark Lutz", "Python. ", 2015, 100.01) # 2. Отобразить книгу на экране book1.display()
Результат выполнения программы
author = Mark Lutz , title = Python. , year = 2015 , price = 100.01
⇑
5. Перегрузка оператора + для класса Point (точка). Пример
Если в классе нужно перегрузить оператор +, то в этом классе нужно реализовать метод __add __(). Общий вид реализации метода __add __() следующий:
class ClassName: def __add__(self, value): # действия, выполняющие суммирование # ... return result # вернуть некоторый результат
После этого можно вызвать метод __add __() как обычную операцию сложения. Например, если нужно добавить два экземпляра класса ClassName, то код будет примерно таким
obj1 = ClassName()
obj2 = ClassName()
...
obj3 = obj1 + obj2 # заменяется на obj3 = obj1.__add__(obj2)
...
Пример. В примере объявляется класс Point, который реализует точку на координатной плоскости. В классе реализованы следующие методы:
- метод __init __(), который перегружает конструктор класса. Конструктор класса вызывается при создании экземпляра класса;
- метод getXY(), который возвращает значение координаты точки (x, y) в виде списка;
- метод __add __() — реализует перегрузку оператора сложения +. Реализация предусматривает суммирование координат по осям X и Y;
- метод Show() — выводит координаты точки на экран.
Ниже приведен текст демонстрационной программы.
# Перегрузка операторов в Python. # Перегрузка оператора (операции) + (сложение). # Класс, который содержит метод __add__() class Point: # Метод инициализации - конструктор def __init__(self, x, y): self.x = x self.y = y # Метод, который возвращает (x, y) в виде списка def getXY(self): return [ self.x, self.y ] # Метод, который перегружает оператор + def __add__(self, point): self.x = self.x + point.x self.y = self.y + point.y return self # Метод, который выводит точку def Show(self, text): print(text, " = (", self.x, "; ", self.y, ")") # Создать точку 1 pt1 = Point(5, 6) pt1.Show("pt1") # Создать точку 2 pt2 = Point(7, 11) pt2.Show("pt2") # Сложить две точки - использовать перегрузку оператора pt3 = pt1 + pt2 # вызов метода __add__() pt3.Show("pt3 = pt1 + pt2")
После запуска на выполнение программа выдаст следующий результат
pt1 = ( 5 ; 6 ) pt2 = ( 7 ; 11 ) pt3 = pt1 + pt2 = ( 12 ; 17 )
⇑
Связанные темы
- Классы в Python. Общие понятия. Ключевое слово class. Объекты классов. Объекты экземпляров
- Наследование в классах. Правила применения наследования. Примеры
⇑