Data Model

Special Methods

Special methods connect your objects to Python syntax and built-ins.

Start with a normal class that stores its data. Special methods build on ordinary instance state.

Source

class Bag:
    def __init__(self, items):
        self.items = list(items)

bag = Bag(["a", "b"])
print(bag.items)

Output

['a', 'b']
a + bdispatchesa.__add__(b)
Operators are method calls. `a + b` dispatches to `a.__add__(b)`; the data model exposes the syntax.

Implement __len__ to let len() ask the object for its size using Python's standard protocol.

Source

class Bag:
    def __init__(self, items):
        self.items = list(items)

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

bag = Bag(["a", "b"])
print(len(bag))

Output

2

Implement __iter__ to make the object iterable. Then tools such as list() can consume it without a custom method name.

Source

class Bag:
    def __init__(self, items):
        self.items = list(items)

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

    def __iter__(self):
        return iter(self.items)

bag = Bag(["a", "b"])
print(list(bag))

Output

['a', 'b']

Implement __repr__ to give the object a useful developer-facing representation when it is printed or inspected. With no __str__ defined, print() falls back to __repr__.

Source

class Bag:
    def __init__(self, items):
        self.items = list(items)

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

    def __iter__(self):
        return iter(self.items)

    def __repr__(self):
        return f"Bag({self.items!r})"

bag = Bag(["a", "b"])
print(bag)

Output

Bag(['a', 'b'])

Add __str__ for an end-user representation. print() and str() prefer __str__; repr() and the REPL still use __repr__. Keep __repr__ unambiguous for debugging and let __str__ be the friendly form.

Source

class Bag:
    def __init__(self, items):
        self.items = list(items)

    def __repr__(self):
        return f"Bag({self.items!r})"

    def __str__(self):
        return ", ".join(self.items)

bag = Bag(["a", "b"])
print(bag)
print(repr(bag))

Output

a, b
Bag(['a', 'b'])

__eq__ decides what equality means for the type. Defining __eq__ removes the default __hash__, so add __hash__ back when instances should work in sets or as dict keys. __lt__ enables < and, with the rest of the order family, sorted().

Source

class Bag:
    def __init__(self, items):
        self.items = list(items)

    def __eq__(self, other):
        return isinstance(other, Bag) and self.items == other.items

    def __hash__(self):
        return hash(tuple(self.items))

    def __lt__(self, other):
        return len(self.items) < len(other.items)

print(Bag(["a", "b"]) == Bag(["a", "b"]))
print(Bag(["a"]) < Bag(["a", "b"]))
print(hash(Bag(["a"])) == hash(Bag(["a"])))

Output

True
True
True

The container protocols make instances behave like built-in containers. __contains__ powers in, __getitem__/__setitem__ power subscription, and __bool__ decides truthiness for if and while. See [container-protocols](/data-model/container-protocols) for the full surface.

Source

class Bag:
    def __init__(self, items):
        self.items = list(items)

    def __contains__(self, item):
        return item in self.items

    def __getitem__(self, index):
        return self.items[index]

    def __setitem__(self, index, value):
        self.items[index] = value

    def __bool__(self):
        return bool(self.items)

bag = Bag(["a", "b"])
print("a" in bag)
print(bag[0])
bag[1] = "z"
print(bag.items)
print(bool(Bag([])))

Output

True
a
['a', 'z']
False

__call__ makes an instance callable like a function — useful for stateful operations whose configuration deserves a name. __enter__ and __exit__ make a class a context manager so it can be used with with. The focused [callable-objects](/data-model/callable-objects) and [context-managers](/data-model/context-managers) pages go deeper.

Source

class Multiplier:
    def __init__(self, factor):
        self.factor = factor

    def __call__(self, value):
        return value * self.factor

triple = Multiplier(3)
print(triple(5))


class Trace:
    def __enter__(self):
        print("enter")
        return self

    def __exit__(self, *exc):
        print("exit")
        return False

with Trace():
    print("inside")

Output

15
enter
inside
exit

Notes

See also

Run the complete example

Example code

Expected output

2
['a', 'b']
a, b
Bag(['a', 'b'])
True
True
True
True
a
['a', 'z']
False
15
enter
inside
exit

Execution time appears here after you run the example.