Перевантаження операторів у класах. Загальні відомості. Методи, що перевантажують оператори. Приклади
Зміст
- 1. Загальні відомості про перевантаження операторів
- 2. Принципи, що лежать в основі перевантаження операторів у класах
- 3. Перелік методів, які можна перевантажувати
- 3.1. Методи для всіх видів операцій
- 3.2. Методи перевантаження операторів роботи з колекціями
- 3.3. Методи для числових операцій у двійковій формі
- 3.4. Методи для інших операцій над числами
- 3.5. Методи для операцій з дескрипторами
- 3.6. Методи для операцій, що використовуються з диспетчерами контексту
- 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, 50.01) # 2. Відобразити книгу на екрані book1.display()
Результат роботи програми
author = Mark Lutz , title = Python. , year = 2015 , price = 50.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. Об’єкти класів. Об’єкти екземплярів
- Спадковість у класах. Правила застосування спадковості. Приклади
⇑