Перейти до основного вмісту
Модуль 7 · Урок 3 із 427/36 у курсі~12 min
Модульні уроки (3/4)

Спеціальні методи (дундер)

Спеціальні методи (називаються методами dunder, оскільки вони починаються і закінчуються з подвійним підкресленням: __name__) є хуками, які дозволяють вашим об’єктам інтеграція з мовою: представлення тексту, порівняння з ==, підтримка операторів len(), in, тощо.

Ви вже використовували один: __init__.

__str__ та __repr__

Вони контролюють те, що відображається за допомогою print() і в REPL.

Python
class Punto:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __repr__(self):
        return f"Punto({self.x}, {self.y})"

    def __str__(self):
        return f"({self.x}, {self.y})"

p = Punto(3, 4)
str(p)        # '(3, 4)'        — per umani
repr(p)       # 'Punto(3, 4)'   — per debugger / dev
print(p)      # '(3, 4)'
p             # Punto(3, 4)     in REPL → repr
[p, p]        # [Punto(3, 4), Punto(3, 4)]   — sempre repr nei contenitori

Якщо ви визначаєте лише __repr__, Python також використовуватиме його як запасний варіант для __str__.

__eq__: перевизначення ==

За умовчанням a == b порівнює ідентифікатори об’єктів (is), а не їх вміст. Для структурного порівняння визначте __eq__:

Python
class Punto:
    def __init__(self, x, y):
        self.x, self.y = x, y

    def __eq__(self, other):
        if not isinstance(other, Punto):
            return NotImplemented
        return (self.x, self.y) == (other.x, other.y)

Punto(1, 2) == Punto(1, 2)    # True
Punto(1, 2) == Punto(3, 4)    # False

Повернення NotImplemented (спеціальне ключове слово, а не False!), коли типи не порівнюються – це правильна практика: тоді Python спробує з інший операнд __eq__.

__len__: підтримка len()

Python
class Cesto:
    def __init__(self):
        self.frutti = []

    def __len__(self):
        return len(self.frutti)

c = Cesto()
c.frutti.append("mela")
len(c)        # 1
bool(c)       # True (len > 0)

Визначивши __len__, ви також безкоштовно отримуєте boolean: об’єкт з len() == 0 стає помилковим.

Інші корисні дандери (огляд)

  • __add__(self, other) → перевизначає +
  • __lt__, __le__, __gt__, __ge__ → оператори порівняння
  • __contains__(self, item) → підтримує item in self
  • __iter__ + __next__ → робить об'єкт ітерованим
  • __getitem__(self, key) → підтримує self[key]
  • __hash__ → має бути ключем dict / елементом набору

Ваша черга

вправи#python.m7.l3.e1
Спроби: 0Завантаження…

Визначте `Money` за допомогою __init__(self, сума, валюта) і __str__, який повертає `f'{amount} {currency}''`. Створіть `s = Money(42, 'EUR')` і обчисліть `str(s)`.

Завантаження редактора…
Показати підказку

f-рядок у __str__.

Рішення доступне після 3 спроб

Повторна вправа

вправи#python.m7.l3.e2
Спроби: 0Завантаження…

Визначте `Pair` за допомогою __init__(self, a, b) і __eq__ на основі структурного порівняння (a, b). Оцініть `Pair(1, 2) == Pair(1, 2)`.

Завантаження редактора…
Показати підказку

Порівняйте кортежі (self.a, self.b) == (other.a, other.b).

Рішення доступне після 3 спроб

Додатковий виклик

вправи#python.m7.l3.e3
Спроби: 0Завантаження…

Визначте клас \`Книга\` з конструктором, який бере \`назву\` та \`автора\`. Визначте спеціальний метод \`__str__(self)\`, щоб він повертав рядок \`"Назва за автором"\` (наприклад, \`'1984 by George Orwell'\`). Створіть екземпляр книги та обчисліть \`str(book)\`.

Завантаження редактора…
Показати підказку

Використовуйте f"{self.title} від {self.author}" всередині def __str__(self):.

Рішення доступне після 3 спроб