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.
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.
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.
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.
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]
penObject 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.
| Special method | Role 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
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.
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
Treating special methods as ordinary methods that users must call directly.
The purpose of a special method is to connect the object to familiar Python syntax or an operation that invokes it automatically.
Fix:
Implement the special method, then use the corresponding syntax such as shelf[1] or a + b.Implementing a differently named helper and expecting bracket notation to use it.
Python translates bracket notation to __getitem__, so another method name is not the indexing protocol described here.
Fix:
Define __getitem__ when the custom object should support obj[key].Putting initial-state setup in an unrelated method.
Python automatically calls __init__ during instance creation, and that method is where the object's initial state is established.
Fix:
Use __init__ to set up the state that the object needs after creation.Assuming __str__ and __repr__ are interchangeable names.
The source distinguishes their purposes and contexts.
Fix:
Choose __str__ for a user-friendly string and __repr__ for a technical representation.
Practice the Translation
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.
Enabling Playlist Indexing
Complete the class so playlist[2] returns the item stored at index 2.
Choose the protocol: Bracket notation is indexing, so the class needs __getitem__.
Receive the key: Define __getitem__(self, key). Python supplies 2 as key when playlist[2] is evaluated.
Return the selected item: Use self.songs[key] and return the resulting value.
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.