Skip to main content
eLearner.app
Module 7 · Lesson 3 of 427/36 in the course~12 min
Module lessons (3/4)

Special methods (dunder)

Special methods (called dunder methods because they begin and end with a double underscore: __name__) are the hooks that let your objects integrate with the language: text representation, comparison with ==, support for len(), in, operators, etc.

You have already used one: __init__.

__str__ and __repr__

They control what appears with print() and in the 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

If you define only __repr__, Python also uses it as a fallback for __str__.

__eq__: redefining ==

By default a == b compares the identifiers of the objects (is), not their contents. For structural comparison, define __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

Returning NotImplemented (a special keyword, not False!) when the types are not comparable is the correct practice: Python will then try with the other operand's __eq__.

__len__: support for 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)

By defining __len__, you also get the boolean for free: an object with len() == 0 becomes falsy.

Other useful dunders (overview)

  • __add__(self, other) → redefines +
  • __lt__, __le__, __gt__, __ge__ → comparison operators
  • __contains__(self, item) → supports item in self
  • __iter__ + __next__ → makes the object iterable
  • __getitem__(self, key) → supports self[key]
  • __hash__ → required to be a dict key / set element

Your turn

Exercise#python.m7.l3.e1
Attempts: 0Loading…

Define `Money` with __init__(self, amount, currency) and __str__ that returns `f'{amount} {currency}'`. Create `s = Money(42, 'EUR')` and evaluate `str(s)`.

Loading editor…
Show hint

f-string in __str__.

Solution available after 3 attempts

Review exercise

Exercise#python.m7.l3.e2
Attempts: 0Loading…

Define `Pair` with __init__(self, a, b) and __eq__ based on the structural comparison of (a, b). Evaluate `Pair(1, 2) == Pair(1, 2)`.

Loading editor…
Show hint

Compare the tuples (self.a, self.b) == (other.a, other.b).

Solution available after 3 attempts

Additional challenge

Exercise#python.m7.l3.e3
Attempts: 0Loading…

Define a class `Book` with a constructor taking `title` and `author`. Define the special method `__str__(self)` so it returns the string `"Title by Author"` (e.g. `'1984 by George Orwell'`). Instantiate a book and evaluate `str(book)`.

Loading editor…
Show hint

Use f"{self.title} by {self.author}" inside def __str__(self):.

Solution available after 3 attempts