Magic methods (or dunder methods) allow your classes to emulate the behavior of built-in types. They are surrounded by double underscores, like __init__.
String Representation
Two key methods control how your object is converted to a string:
__repr__(self): The "official" string representation. It should ideally look like a valid Python expression that could recreate the object. Used by the debugger and the interactive console.__str__(self): The "informal" string representation. Used by print() and str(). If __str__ isn't defined, Python falls back to __repr__.
Comparison
To make your objects comparable (e.g., using ==, <), implement these methods:
__eq__(self, other): Equality (==)__lt__(self, other): Less than (<)__le__, __gt__, __ge__, __ne__
Note: __ne__ delegates to __eq__ by default if not implemented.
Arithmetic
You can define how operators interact with your objects:
__add__(self, other): Addition (+)__sub__(self, other): Subtraction (-)__mul__(self, other): Multiplication (*)
Hashing
If you implement __eq__, your object becomes unhashable (cannot be used in sets or as dict keys) unless you also implement __hash__. The hash must be an integer and must be consistent for equal objects. Mutable objects should generally not be hashable.