Przejdź do głównej treści
eLearner.app
Moduł 7 · Lekcja 3 z 427/36 w kursie~12 min
Lekcje modułu (3/4)

Metody specjalne (dunder)

Metody specjalne (nazywane metodami dunder ponieważ zaczynają się i kończą podwójnym znakiem podkreślenia: __name__) to mechanizmy pozwalające integrować Twoje obiekty z samym językiem: reprezentacja tekstowa, porównywanie za pomocą ==, obsługa funkcji len(), operatora in, operatorów matematycznych itp.

Znasz już jedną z nich: __init__.

__str__ oraz __repr__

Kontrolują to, co jest wyświetlane przy użyciu print() oraz w konsoli 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)'        — dla ludzi
repr(p)       # 'Punto(3, 4)'   — dla debuggera / programisty
print(p)      # '(3, 4)'
p             # Punto(3, 4)     w konsoli REPL → wywołuje repr
[p, p]        # [Punto(3, 4), Punto(3, 4)]   — w kontenerach zawsze używa repr

Jeśli zdefiniujesz tylko __repr__, Python użyje jej również jako alternatywy dla __str__.

__eq__: redefiniowanie operatora ==

Domyślnie operator == porównuje tożsamość obiektów (is), a nie ich zawartość. Do porównania strukturalnego zdefiniuj metodę __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

Zwrócenie wartości NotImplemented (specjalne słowo kluczowe, a nie False!), gdy typy nie są porównywalne, jest najlepszą praktyką: Python spróbuje wtedy użyć metody __eq__ drugiego operandu.

__len__: obsługa funkcji 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)

Definiując __len__, otrzymujesz również zachowanie boolean za darmo: obiekt z len() == 0 będzie traktowany jako fałsz (falsy).

Inne przydatne metody specjalne (przegląd)

  • __add__(self, other) → redefiniuje operator +
  • __lt__, __le__, __gt__, __ge__ → operatory porównania
  • __contains__(self, item) → obsługuje warunek item in self
  • __iter__ + __next__ → sprawia, że obiekt jest iterowalny
  • __getitem__(self, key) → pozwala na zapis self[key]
  • __hash__ → wymagana, by obiekt mógł być kluczem w słowniku lub elementem zbioru

Spróbuj sam

Ćwiczenie#python.m7.l3.e1
Próby: 0Ładowanie...

Zdefiniuj klasę `Money` z konstruktorem __init__(self, amount, currency) oraz metodą __str__ zwracającą `f'{amount} {currency}'`. Utwórz `s = Money(42, 'EUR')` i oceń `str(s)`.

Ładowanie edytora...
Pokaż wskazówkę

Zastosuj f-string w metodzie __str__.

Rozwiązanie dostępne po 3 próbach

Ćwiczenie powtórzeniowe

Ćwiczenie#python.m7.l3.e2
Próby: 0Ładowanie...

Zdefiniuj klasę `Pair` z konstruktorem __init__(self, a, b) oraz metodą __eq__ porównującą strukturę (a, b). Oceń `Pair(1, 2) == Pair(1, 2)`.

Ładowanie edytora...
Pokaż wskazówkę

Porównaj krotki (self.a, self.b) == (other.a, other.b).

Rozwiązanie dostępne po 3 próbach

Dodatkowe wyzwanie

Ćwiczenie#python.m7.l3.e3
Próby: 0Ładowanie...

Zdefiniuj klasę `Book` z konstruktorem przyjmującym `title` i `author`. Zdefiniuj metodę specjalną `__str__(self)` tak, aby zwracała ciąg znaków `"Title by Author"` (np. `'1984 by George Orwell'`). Utwórz obiekt książki i oceń `str(book)`.

Ładowanie edytora...
Pokaż wskazówkę

Użyj zapisu f"{self.title} by {self.author}" wewnątrz def __str__(self):.

Rozwiązanie dostępne po 3 próbach