Однією з менш відомих, проте дуже корисних можливостей мови Python є реалізація магічних методів у об’єктах. Застосовуючи магічні методи, ми можемо створювати більш зрозумілий, інтуїтивний та простий для сприйняття код.
Магічні методи дозволяють нам розробляти інтерфейси для взаємодії з об’єктами, які виглядають більш “pythonic”. У цій статті ми розглянемо магічні методи, обговоримо найкращі практики їх використання, а також дослідимо поширені магічні методи, з якими ви можете зіткнутися.
Що таке магічні методи?
Магічні методи – це спеціальні методи в Python, які визначають поведінку об’єктів під час виконання стандартних операцій. Ці методи відрізняються тим, що їхні назви починаються і закінчуються двома символами підкреслення.
Через подвійне підкреслення їх також часто називають методами dunder. Наприклад, метод `__init__()`, який використовується для створення конструкторів класів, є поширеним прикладом методу dunder.
Зазвичай, методи dunder не викликаються безпосередньо у коді; їх викликає інтерпретатор під час виконання програми.
Чому магічні методи є корисними?
Магічні методи – це важлива концепція в об’єктно-орієнтованому програмуванні на Python. Вони дозволяють задавати поведінку власних типів даних при використанні звичайних операцій, таких як:
- Арифметичні операції
- Операції порівняння
- Операції життєвого циклу
- Операції представлення
У наступних розділах ми розглянемо, як реалізовувати магічні методи для визначення поведінки програми при використанні в усіх зазначених категоріях.
Як визначити магічні методи
Як було зазначено, магічні методи визначають поведінку об’єктів. Тому вони є частиною класу об’єкта. Оскільки вони є частиною класу, вони приймають `self` як перший аргумент, який є посиланням на сам об’єкт.
В залежності від того, як їх викликає інтерпретатор, вони можуть приймати додаткові аргументи. І, як було згадано раніше, їхні назви починаються і закінчуються двома символами підкреслення.
Реалізація
Багато з того, що ми обговорювали, може здаватися теоретичним. У цьому розділі ми реалізуємо простий клас `Rectangle` (Прямокутник).
Цей клас матиме атрибути `length` (довжина) та `width` (ширина). За допомогою методу `__init__` ми зможемо задавати ці атрибути при створенні екземпляра класу. Також, ми зможемо порівнювати прямокутники на рівність, “менше” чи “більше” за допомогою операторів `==`, `<` та `>`. І, звичайно, наш прямокутник повинен мати можливість генерувати осмислене рядкове представлення.
Налаштування середовища розробки
Для виконання цього прикладу вам знадобиться середовище виконання Python. Ви можете використовувати локальний компілятор або онлайн-компілятор.
Створення класу Rectangle
Спочатку визначимо клас `Rectangle`.
class Rectangle: pass
Створення методу конструктора
Тепер створимо наш перший магічний метод – конструктор класу. Цей метод буде приймати висоту та ширину і зберігати їх як атрибути екземпляра класу.
class Rectangle: def __init__(self, height, width): self.height = height self.width = width
Створення магічного методу для рядкового представлення
Далі ми хочемо створити метод, який дозволить нашому класу генерувати зрозуміле для людини рядкове представлення об’єкта. Цей метод буде викликатися кожен раз, коли ми викликаємо функцію `str()`, передаючи екземпляр класу `Rectangle` як аргумент. Цей метод також буде викликатися функціями, які очікують рядковий аргумент, наприклад функцією `print`.
class Rectangle: def __init__(self, height, width): self.height = height self.width = width def __str__(self): return f'Rectangle({self.height}, {self.width})'
Метод `__str__()` повинен повертати рядок, що представляє об’єкт. В цьому випадку ми повертаємо рядок у форматі `Rectangle(
Створення магічних методів для операцій порівняння
Далі ми створимо оператори порівняння для операцій “дорівнює”, “менше” та “більше”. Це називається перевантаженням операторів. Для цього ми використовуємо магічні методи `__eq__`, `__lt__` та `__gt__` відповідно. Ці методи будуть повертати булеве значення, порівнюючи площі прямокутників.
class Rectangle: def __init__(self, height, width): self.height = height self.width = width def __str__(self): return f'Rectangle({self.height}, {self.width})' def __eq__(self, other): """ Перевірка на рівність """ return self.height * self.width == other.height * other.width def __lt__(self, other): """ Перевірка, чи прямокутник менший за інший """ return self.height * self.width < other.height * other.width def __gt__(self, other): """ Перевірка, чи прямокутник більший за інший """ return self.height * self.width > other.height * other.width
Як бачите, ці методи приймають два параметри. Перший – це поточний прямокутник (`self`), а другий – інше значення, з яким його порівнюють (`other`). Це може бути інший екземпляр `Rectangle` або будь-яке інше значення. Логіка порівняння та умови, за яких порівняння повертатиме `True`, повністю залежать від вашої реалізації.
Поширені магічні методи
У цьому розділі ми розглянемо деякі загальні магічні методи, з якими ви найчастіше будете стикатися та використовувати.
#1. Арифметичні операції
Арифметичні магічні методи викликаються, коли екземпляр вашого класу знаходиться ліворуч від арифметичного знаку. Метод викликається з двома аргументами, перший з яких є посиланням на екземпляр (`self`), а другий – об’єкт праворуч від знака. Ось основні арифметичні методи:
Назва | Метод | Знак | Опис |
Додавання | `__add__` | `+` | Реалізує додавання. |
Віднімання | `__sub__` | `–` | Реалізує віднімання. |
Множення | `__mul__` | `*` | Реалізує множення. |
Ділення | `__div__` | `/` | Реалізує ділення. |
Цілочисельне ділення | `__floordiv__` | `//` | Реалізує цілочисельне ділення. |
#2. Операції порівняння
Так само, як і арифметичні методи, ці методи викликаються, коли екземпляр класу розміщується ліворуч від оператора порівняння. Вони також приймають два параметри: посилання на екземпляр (`self`) та посилання на значення з правого боку знака.
Назва | Метод | Знак | Опис |
Менше ніж | `__lt__` | `<` | Реалізує порівняння “менше ніж”. |
Більше ніж | `__gt__` | `>` | Реалізує порівняння “більше ніж”. |
Дорівнює | `__eq__` | `==` | Реалізує порівняння на рівність. |
Менше або дорівнює | `__le__` | `<=` | Реалізує порівняння “менше або дорівнює”. |
Більше або дорівнює | `__ge__` | `>=` | Реалізує порівняння “більше або дорівнює”. |
#3. Операції життєвого циклу
Ці методи викликаються у відповідь на різні події життєвого циклу об’єкта, наприклад, його створення або видалення. До цієї категорії відноситься конструктор `__init__`. Ось основні методи цієї категорії:
Назва | Метод | Опис |
Конструктор | `__init__` | Цей метод викликається при створенні нового екземпляра класу. |
Видалення | `__del__` | Цей метод викликається при видаленні об’єкта класу. Його можна використовувати для очищення, наприклад, закриття відкритих файлів. |
Створення | `__new__` | Метод `__new__` викликається першим при створенні екземпляра об’єкта. Він викликається перед конструктором і приймає клас, а також будь-які додаткові аргументи. Він повертає екземпляр класу. |
#4. Операції представлення
Назва | Метод | Опис |
Рядкове представлення | `__str__` | Повертає зрозуміле для людини рядкове представлення об’єкта. Цей метод викликається функцією `str()`, а також функціями `print()` та `format()`. Він призначений для надання рядка, який буде зрозумілий кінцевому користувачеві програми. |
Представлення для розробника | `__repr__` | Повертає рядкове представлення об’єкта, яке використовується розробником. В ідеалі, цей рядок повинен містити достатньо інформації для створення ідентичного екземпляра об’єкта. |
Найкращі практики створення магічних методів
Магічні методи є дуже потужним інструментом, який може спростити ваш код. Однак, при їх використанні важливо пам’ятати наступне:
- Використовуйте їх ощадливо – надмірна кількість магічних методів у ваших класах може ускладнити розуміння коду. Зосередьтеся на реалізації тільки найважливіших.
- Перед використанням таких методів, як `__setattr__` та `__getattr__`, переконайтеся, що ви розумієте вплив на продуктивність таких методів.
- Задокументуйте поведінку ваших магічних методів, щоб інші розробники могли точно знати, що вони роблять. Це полегшить їх використання та відлагодження.
Заключні слова
У цій статті я представив магічні методи як спосіб створення класів, які можна використовувати з вбудованими операціями. Я також розповів про те, як вони визначаються, розглянув приклад класу, що реалізує магічні методи, та згадав різні методи, які ви, ймовірно, будете використовувати. Наостанок, ми поговорили про деякі найкращі практики, які слід пам’ятати.
Наступним кроком для вас може стати вивчення, як реалізувати клас `Counter` у Python.