Data Model Customization — Core Concepts

What Is the Data Model?

Python’s data model is the framework that defines how objects interact with the language itself. When you write a + b, Python doesn’t hard-code addition — it calls a.__add__(b). When you write len(x), Python calls x.__len__(). When you write for item in collection, Python calls collection.__iter__().

This design means any object can participate in Python’s syntax — as long as it implements the right special methods.

The Major Categories

Representation and Display

MethodTriggered ByPurpose
__repr__repr(obj), debuggerUnambiguous developer representation
__str__str(obj), print(obj)Human-readable display
__format__f"{obj:spec}", format(obj)Custom formatting
__bool__if obj:, bool(obj)Truthiness

Rule of thumb: __repr__ should be unambiguous (ideally copy-pasteable to recreate the object). __str__ should be readable.

Comparison

MethodOperator
__eq__==
__ne__!=
__lt__<
__le__<=
__gt__>
__ge__>=

Implementing __eq__ and __lt__ (plus using @functools.total_ordering) gives you all six comparisons.

Arithmetic

MethodOperatorReflected Version
__add__+__radd__
__sub__-__rsub__
__mul__*__rmul__
__truediv__/__rtruediv__
__mod__%__rmod__
__pow__**__rpow__

Reflected methods (__radd__, etc.) are called when the left operand doesn’t know how to handle the operation. If a + b fails via a.__add__(b), Python tries b.__radd__(a).

Container Behavior

MethodMakes Object Work Like
__len__len(obj)
__getitem__obj[key], iteration fallback
__setitem__obj[key] = value
__delitem__del obj[key]
__contains__item in obj
__iter__for item in obj
__reversed__reversed(obj)

Callable Objects

MethodTriggered By
__call__obj()

Making an object callable is powerful for creating function-like objects that maintain state.

Context Managers

MethodTriggered By
__enter__with obj as x: (start)
__exit__End of with block

How Operators Actually Work

When Python encounters a + b:

  1. Check if type(b) is a subclass of type(a). If so, try b.__radd__(a) first (gives subclasses priority).
  2. Try a.__add__(b).
  3. If that returns NotImplemented, try b.__radd__(a).
  4. If that also returns NotImplemented, raise TypeError.

The NotImplemented singleton (not NotImplementedError!) is Python’s way for an operator method to say “I don’t know how to handle this type.”

Building a Complete Custom Type

A well-integrated custom type typically implements:

  1. __init__ — construction
  2. __repr__ and __str__ — representation
  3. __eq__ and __hash__ — equality and hashing (needed for sets and dict keys)
  4. Domain-specific operators — whatever makes sense for the type

Why __hash__ Matters

If you implement __eq__, Python automatically sets __hash__ to None, making your object unhashable. If you need the object to work as a dictionary key or set member, you must also implement __hash__ — and ensure equal objects have equal hashes.

Common Misconception

“Special methods are just syntactic sugar.” They’re more than that. Many special methods are called by CPython’s C-level infrastructure directly, bypassing normal attribute lookup for performance. For example, len() calls the sq_length slot at the C level, not __len__ through Python’s attribute system. This means you can’t intercept these calls with __getattribute__.

Practical Tips

  • Start with __repr__ — it’s the most useful single special method. Good repr makes debugging 10x easier.
  • Return NotImplemented from operator methods when you receive an unfamiliar type — don’t raise TypeError yourself.
  • Don’t implement operators that don’t make sense. A User class shouldn’t support + just because it can.
  • Use @functools.total_ordering to avoid writing all six comparison methods manually.

One thing to remember: Python’s data model is a set of special methods that let your objects plug into the language’s syntax. Implement the right methods, and your objects can use +, in, for, with, len(), and more — becoming first-class citizens of the language.

pythonadvancedoopinternals

See Also

  • Python Attribute Lookup Chain How Python finds your variables and methods — like checking your pockets, then your bag, then your locker, in a specific order every time.
  • Python Bytecode And Interpreter How your .py file turns into tiny instructions the Python interpreter can execute step by step.
  • Python Class Body Execution Python runs the code inside your class definition immediately — like reading a recipe out loud before anyone starts cooking.
  • Python Garbage Collection See how Python cleans up unreachable objects, especially the tricky ones that point at each other.
  • Python Gil Why Python threads can feel stuck in traffic, and how the GIL explains the behavior.