Salt la conținutul principal
Modulul 7 · Lecția 3 din 427/36 în curs~12 min
Lecții din modul (3/4)

Metode speciale (dunder)

Metode speciale (numite metode dunder pentru că încep și se termină cu liniuță dublă: __name__) sunt cârligele care lasă obiectele tale se integrează cu limba: reprezentare text, comparație cu ==, suport pentru len(), in, operatori etc.

Ați folosit deja unul: __init__.

__str__ și __repr__

Ei controlează ceea ce apare cu print() și în 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

Dacă definiți doar __repr__, Python îl folosește și ca alternativă pentru __str__.

__eq__: redefinirea ==

În mod implicit, a == b compară identificatorii obiectelor (is), nu continutul lor. Pentru comparație structurală, definiți __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

Se returnează NotImplemented (un cuvânt cheie special, nu False!) când tipurile nu sunt comparabile este practica corectă: Python va încerca apoi cu alt operand __eq__.

__len__: suport pentru 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)

Prin definirea __len__, obțineți și boolean gratuit: un obiect cu len() == 0 devine fals.

Alte lucruri utile (prezentare generală)

  • __add__(self, other) → redefinește +
  • __lt__, __le__, __gt__, __ge__ → operatori de comparație
  • __contains__(self, item) → acceptă item in self
  • __iter__ + __next__ → face obiectul iterabil
  • __getitem__(self, key) → acceptă self[key]
  • __hash__ → trebuie să fie o cheie dict / element de set

Rândul tău

Exercițiu#python.m7.l3.e1
Încercări: 0Se încarcă…

Definiți `Bani` cu __init__(self, amount, currency) și __str__ care returnează `f'{amount} {currency}'`. Creați `s = Money(42, 'EUR')` și evaluați `str(s)`.

Se încarcă editorul...
Afișează indiciu

șir f în __str__.

Soluție disponibilă după 3 încercări

Exercițiu de revizuire

Exercițiu#python.m7.l3.e2
Încercări: 0Se încarcă…

Definiți `Pereche` cu __init__(self, a, b) și __eq__ pe baza comparației structurale a (a, b). Evaluați `Pair(1, 2) == Pair(1, 2)`.

Se încarcă editorul...
Afișează indiciu

Comparați tuplurile (self.a, self.b) == (other.a, other.b).

Soluție disponibilă după 3 încercări

Provocare suplimentară

Exercițiu#python.m7.l3.e3
Încercări: 0Se încarcă…

Definiți o clasă \`Carte\` cu un constructor care ia \`titlu\` și \`autor\`. Definiți metoda specială \`__str__(self)\` astfel încât să returneze șirul \`"Titlu după autor"\` (de exemplu, \`'1984 de George Orwell'\`). Instanciați o carte și evaluați \`str(book)\`.

Se încarcă editorul...
Afișează indiciu

Folosiți f"{self.title} de {self.author}" în def __str__(self):.

Soluție disponibilă după 3 încercări