Back to Blog
Python

Python __radd__: Reverse Addition Explained

python **radd**: Understand Python's __radd__ method: when it's called, how to implement it, and common pitfalls when overloading addition for custom types.

dunder methodsoperator overloadingPython internalsnumeric typesobject-oriented programming
Diagram showing two objects and the plus operator with a reversed arrow indicating the __radd__ method call

When you write a + b in Python, the interpreter does not simply add two values. It first attempts a.__add__(b). If a does not define __add__, or if that method returns NotImplemented, Python then tries b.__radd__(a). This reverse addition method is what allows your custom class to participate in addition even when it appears on the right-hand side of the operator. Understanding python **radd** is essential for building numeric types, vector classes, or any object that should behave like a number.

When Python Calls radd

The dispatch mechanism for the + operator follows a strict order. For an expression left + right, Python checks left.__add__(right) first. If that method is absent or returns NotImplemented, Python then checks right.__radd__(left). The reverse method is called with the left operand as its argument. This is why __radd__ is often described as the "reflected" or "reverse" addition.

Consider a simple example. Suppose you have a class Number that defines __radd__ but not __add__. When you write 2 + Number(3), Python first tries (2).__add__(Number(3)), which returns NotImplemented because the built-in int does not know how to handle a Number instance. Python then calls Number(3).__radd__(2), which can return a meaningful result.

A Minimal radd Implementation

Here is a basic implementation of __radd__ for a custom numeric wrapper:

class Number: def __init__(self, value): self.value = value def __radd__(self, other): return Number(self.value + other) def __repr__(self): return f"Number({self.value})"

Now you can write:

result = 5 + Number(3) print(result) # Number(8)

Note that __radd__ receives the left operand (other) and must return a new object or a value. In this example, it returns a Number instance, preserving the type. If you want Number + Number to work as well, you would also need __add__.

Returning NotImplemented vs Raising TypeError

A common mistake is to raise TypeError directly from __radd__ when the operation is not supported. The correct approach is to return the special value NotImplemented. This tells Python that the operation cannot be handled, and Python will then raise a TypeError with an appropriate message, or try another fallback if one exists.

class Number: def __radd__(self, other): if isinstance(other, (int, float)): return Number(self.value + other) return NotImplemented

Returning NotImplemented instead of raising an exception allows Python to try the reverse operation on the other operand, and it also makes your class cooperate better with subclasses and multiple dispatch.

Interaction with Subclasses and Type Hierarchies

The order of method resolution changes when subclasses are involved. Python gives priority to the subclass's method, regardless of whether it is __add__ or __radd__. For example, if Sub is a subclass of Base, and both define the appropriate methods, Sub's method is called first, even if Sub is on the right side. This rule prevents the base class from silently overriding the subclass's behavior.

Consider this scenario:

class Base: def __add__(self, other): return "Base add" def __radd__(self, other): return "Base radd" class Sub(Base): def __add__(self, other): return "Sub add" def __radd__(self, other): return "Sub radd"

When you evaluate Base() + Sub(), Python calls Sub.__radd__ first because Sub is a subclass of Base. The result is "Sub radd". This behavior is defined in the Python data model and is important to remember when designing class hierarchies.

Practical Use: Custom Numeric Types

A realistic use case for __radd__ is building a class that represents a measurement with units. For instance, a Distance class that stores meters should support adding a plain number (interpreted as meters) from either side.

class Distance: def __init__(self, meters): self.meters = meters def __add__(self, other): if isinstance(other, Distance): return Distance(self.meters + other.meters) if isinstance(other, (int, float)): return Distance(self.meters + other) return NotImplemented def __radd__(self, other): return self.__add__(other)

Here, __radd__ simply delegates to __add__ because addition is commutative for this type. This pattern is common and avoids duplicating logic. However, if your operation is not commutative, you must implement __radd__ separately to handle the reversed operand order.

Common Pitfalls and Edge Cases

One pitfall is forgetting that __radd__ is only called when the left operand's __add__ fails. If your class defines __add__ but it returns NotImplemented for certain types, __radd__ will be invoked only if the right operand supports it. If neither returns a valid result, Python raises TypeError.

Another edge case involves mutable objects. If your __radd__ modifies self instead of returning a new object, you will get surprising behavior, especially in expressions like total += value. The += operator uses __add__ (or __iadd__ if defined) and expects a new object or an in-place modification that still returns the result. Returning NotImplemented from __radd__ is safer than raising an exception because it allows Python to fall back to other mechanisms.

Design and Maintainability Considerations

Implementing __radd__ correctly requires thinking about type contracts and the semantics of your operation. For commutative operations, delegating to __add__ keeps the code DRY. For non-commutative operations, you must carefully document which operand is which. Overloading operators can make code more readable, but it also adds a layer of indirection that can confuse maintainers if the behavior is not intuitive. Always include docstrings and type hints to clarify the expected types and return values.

Performance is rarely a concern with __radd__ itself, but the dispatch mechanism involves a few extra attribute lookups. In performance-critical loops, you might prefer explicit method calls over operator overloading. However, for most application code, the readability benefits outweigh the negligible overhead. The key is to ensure that your __radd__ returns NotImplemented quickly for unsupported types, avoiding expensive type checks or conversions that could slow down the common path.

python **radd**: Practical Usage and Code Examples | RYUSLOG DEV