Concepts / Magic Methods and Protocols

Magic Methods and Protocols

Special methods are methods with double underscores that have special significance in Python classes. They are called automatically by Python in response to specific operations or syntax.

  • Programming

From Familiar Syntax to Hidden Calls

Python lets you write expressions such as a + b, len(items), and items[key] without explicitly calling a method. For objects that support these operations, Python connects the syntax to a special method behind the scenes. Special methods are methods with double underscores that have special significance in Python classes. They allow custom objects to behave like built-in types and make those objects feel natural to use.

a + baddition syntax__add__method on alen(obj)length operation__len__method on objobj[key]bracket notation__getitem__method on objconnects toconnects toconnects to
Which special method does Python connect to when code uses an operator, a built-in operation, or bracket notation?

Protocols Behind Standard Operations

A protocol is the operation-specific behavior that an object provides through the relevant special method. Indexing uses the indexing protocol, which is represented by __getitem__. Addition uses the method associated with addition, __add__. Other operations have their own corresponding special methods. Python uses the same mechanism for built-in types and custom classes: a list supports bracket notation through the same kind of protocol that a custom class can implement.

Iterationoperation behavior__getitem__custom methodCustom objectsupports selected protocolsIndexingoperation behaviorComparisonoperation behaviorrequires matching behaviorusesrequires matching behaviorimplemented by
How do standard Python operations connect to the methods a custom object provides?
Key point

Implementing a special method is not merely adding a differently named helper. It connects the object to a standard Python operation. Once the appropriate method exists, users can use familiar syntax instead of learning a separate method name for every operation.

Tracing Bracket Notation

The clearest example is indexing. When Python evaluates obj[key], it translates that bracket notation into a call to obj.__getitem__(key). The key is passed into __getitem__, and the value returned by that method becomes the result of the indexing expression.

catalog[1]bracket notation1key passed to method__getitem__receives key 1catalog itemreturned valueextractspassesreturns
What happens to the key in obj[key] before Python produces the result?
Code walkthrough
class Shelf:
    def __init__(self, items):
        self.items = items

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

shelf = Shelf(["notebook", "pen", "ruler"])
chosen = shelf[1]
  1. 1
    The __init__ method stores the supplied collection as the object's initial state.
  2. 2
    The __getitem__ method receives the key used inside bracket notation.
  3. 3
    When shelf[1] is evaluated, Python calls shelf.__getitem__(1).
  4. 4
    The method uses that key to select an item from self.items and returns the selected value.
Output
pen

Object Lifecycle Methods

Some special methods govern an object's lifecycle rather than an operator. When you create an instance with MyClass(args), Python first allocates memory for the new object and then automatically calls __init__ with the supplied arguments. The __init__ method establishes the object's initial state. After it completes, the initialized object is returned to you.

MyClass(args)creation expressionNew objectmemory allocated__init__initial state setInitialized objectavailable to use__del__cleanup opportunitystartscallsproduceswhen no longer needed
Which lifecycle methods are associated with creating an object and with its later disposal?
Special methodRole described in the source
__init__Initializes an object's state
__del__Allows cleanup code when an object is about to be garbage collected
__getitem__Enables indexing and bracket notation
__str__Controls a user-friendly string form
__repr__Controls a technical string representation

Common special methods and the behavior they control

python

In this example, __init__ gives the object its initial name. The __del__ method contains cleanup code that Python can call when the object is no longer needed and is about to be garbage collected. These methods belong to different points in the object's lifecycle: one establishes state, while the other provides an opportunity for cleanup.

Making Objects Readable

The special methods __str__ and __repr__ control how an object appears as text. They are related but serve different purposes and are called in different contexts. A class can implement them so that its objects present a user-friendly form and a technical representation appropriate to the context.

python

The exact text returned by these methods is chosen by the class designer. The key idea is separation of purpose: __str__ supplies a user-friendly string, while __repr__ supplies a technical string representation. Together with methods such as __init__ and __getitem__, they help a custom class integrate with ordinary Python usage.

Mistakes with Special Methods

  • Common mistake

    Treating special methods as ordinary methods that users must call directly.

    What it looks like

    Writing shelf.__getitem__(1) as the normal public interface instead of supporting shelf[1].

    Why it fails

    The purpose of a special method is to connect the object to familiar Python syntax or an operation that invokes it automatically.

    Do this instead

    Implement the special method, then use the corresponding syntax such as shelf[1] or a + b.

  • Common mistake

    Implementing a differently named helper and expecting bracket notation to use it.

    What it looks like

    Defining get_item but not defining __getitem__.

    Why it fails

    Python translates bracket notation to __getitem__, so another method name is not the indexing protocol described here.

    Do this instead

    Define __getitem__ when the custom object should support obj[key].

  • Common mistake

    Putting initial-state setup in an unrelated method.

    What it looks like

    Creating an object without setting its required attributes in __init__.

    Why it fails

    Python automatically calls __init__ during instance creation, and that method is where the object's initial state is established.

    Do this instead

    Use __init__ to set up the state that the object needs after creation.

  • Common mistake

    Assuming __str__ and __repr__ are interchangeable names.

    What it looks like

    Using one method without considering whether the desired result is user-friendly or technical.

    Why it fails

    The source distinguishes their purposes and contexts.

    Do this instead

    Choose __str__ for a user-friendly string and __repr__ for a technical representation.

Practice the Translation

EASY

A class named Playlist stores a collection in self.songs. Write the special method that allows an expression such as playlist[2] to return the third stored song. Then describe the method call Python connects to that expression.

Hints
  • Bracket notation uses the indexing protocol.
  • The key or index is passed into the special method.
  • The method should use the received key to select from self.songs.
Worked example

Enabling Playlist Indexing

Complete the class so playlist[2] returns the item stored at index 2.

  1. 1
    Choose the protocol

    Bracket notation is indexing, so the class needs __getitem__.

  2. 2
    Receive the key

    Define __getitem__(self, key). Python supplies 2 as key when playlist[2] is evaluated.

  3. 3
    Return the selected item

    Use self.songs[key] and return the resulting value.

Result

The completed behavior is represented by: def __getitem__(self, key): return self.songs[key]. Python connects playlist[2] to playlist.__getitem__(2).

The Pythonic Design Principle

Special methods provide a bridge between a class and Python's standard language behavior. The class supplies the method, while Python supplies the automatic invocation when the matching syntax or operation appears. This shared mechanism is used by built-in types and custom classes, so implementing the right methods lets custom objects participate in familiar Python operations.

  • Double-underscore methods have special significance and are invoked automatically for specific operations or syntax.
  • Operators and bracket notation connect to corresponding special methods, such as __add__ for addition and __getitem__ for indexing.
  • __init__ establishes an object's initial state, while __del__ provides cleanup code when the object is about to be garbage collected.
  • __str__ and __repr__ control different forms of an object's textual representation.
  • Protocols let custom classes behave like built-in types and fit naturally into Python code.

Key Takeaways

  • Special methods are double-underscore methods that Python invokes automatically in response to particular operations or syntax.
  • Python connects expressions such as a + b and obj[key] to methods such as __add__ and __getitem__.
  • __init__ initializes an object's state, and __del__ provides an opportunity for cleanup when the object is about to be garbage collected.
  • __str__ provides a user-friendly string form, while __repr__ provides a technical representation.
  • Implementing the appropriate protocol allows a custom class to feel like a familiar built-in type.

Related concepts

More concepts starting with M