skip to content

When does Python try the right operand's __radd__ before the left operand's __add__?

level: seniorimportance: nice to knowfreq 18%

answer

  1. The usual left-first order has one exception
  2. It depends on the relationship between the two types
  3. The more specific type gets first refusal
  4. Inheriting the method is not enough
  5. Proper subclass that overrides the reflected method

basics

~20 s

When the right operand's type is a proper subclass of the left operand's type and actually overrides the reflected method. Python gives the more specific type first refusal, because the base class was written before the subclass existed.

solid answer

~40 s

The usual order is left-operand first, with `__radd__` consulted only after `__add__` returns `NotImplemented`. There is one documented exception: if `type(right)` is a proper subclass of `type(left)` **and** supplies its own reflected method rather than inheriting the base's, Python calls `type(right).__radd__` first. The reasoning is specificity plus chronology — the base class cannot know about a subclass written later, while the subclass was written knowing the base, so it gets first refusal. Both conditions matter: a subclass that merely inherits `__radd__` gets the ordinary left-first order. If the override returns `NotImplemented`, the interpreter falls back to the base's `__add__` as usual, so declining is how a subclass asks for the inherited behaviour. Two instances of the *same* class never reach the reflected method at all.

code

python · 16 lines
python
class Interval:
    def __add__(self, other):
        return "Interval.__add__"


class Exon(Interval):
    def __radd__(self, other):
        return "Exon.__radd__"


class Gap(Interval):
    pass


print(Interval() + Exon())     # subclass overrides __radd__ -> reflected first
print(Interval() + Gap())      # no override -> ordinary left-first order

go deeper

for a junior

Recall only the default: the left operand's method runs first and the reflected one is a fallback. The subclass exception is not expected of you, but knowing that one exists is a good sign.

for a middle

Be able to state the exception precisely and name both conditions: a proper subclass on the right, and an actual override of the reflected method rather than an inherited one. Show that you have read the data-model rule rather than guessed it.

for a senior

Explain the design reason — the more specific type is the only one that could have been written knowing the other — and the discipline it implies: an override must return NotImplemented in the cases it does not want, or it silently pre-empts the base class for every mixed expression.

for a principal

Frame it as a subclassing contract. Decide whether your types are meant to be subclassed for arithmetic at all, keep left and right placement symmetric, and treat an asymmetric operator introduced by a reflected override as an API defect worth catching in review.

### The default, and the one exception to it For a binary operator the usual order is left-operand first: `left + right` asks `type(left).__add__` and only consults `type(right).__radd__` when the first call returns `NotImplemented`. There is exactly one documented exception. **If `type(right)` is a proper subclass of `type(left)` *and* it overrides the reflected method, Python calls the reflected method first.** Both conditions matter, and candidates usually remember only the first: ```python class Interval: def __add__(self, other): return "Interval.__add__" class Exon(Interval): def __radd__(self, other): return "Exon.__radd__" class Gap(Interval): pass Interval() + Exon() # 'Exon.__radd__' subclass overrides -> reflected first Interval() + Gap() # 'Interval.__add__' no override -> ordinary left-first order ``` "Overrides" is checked against the left operand's type: the right type must supply a reflected method that is not the same object as the one the left type would use. A subclass that merely inherits the base's `__radd__` — or defines nothing at all — does not qualify, and the ordinary left-first order applies. ### Why the rule exists It is a specificity rule, and the argument is about time. A base class is written before its subclasses exist, so `Interval.__add__` cannot know what an `Exon` is; it will either produce a plain `Interval` (silently downgrading the more specific type) or blindly succeed with the wrong semantics. The subclass, by contrast, was written *knowing* the base, so it is the only one of the two that can make an informed decision. Python therefore gives the more specific type first refusal whenever it has bothered to express an opinion by overriding the reflected method. The pattern generalises: whenever a subclass wants different behaviour with a base instance on the **left**, `__radd__` (and its siblings) is the hook, because `__add__` on that expression belongs to the base. ### Living with the rule as an author Three consequences worth stating out loud: * **Your override wins, so it must be able to lose.** A reflected method that always returns a result silently pre-empts the base class for every mixed expression. If your subclass only wants to handle some cases, return `NotImplemented` for the rest — Python then falls back to the base's `__add__` exactly as it would have without the override. * **The order flips depending on which side you are on.** `base + sub` reaches your `__radd__` and `sub + base` reaches your `__add__` (inherited or not). A subclass that handles one direction and forgets the other produces an asymmetric operator, which is a hard bug to read in a traceback because the two expressions look symmetric on the page. * **Same-type operands skip reflection entirely.** For two instances of one class the reflected method is not consulted at all: `__add__` runs once, and a `NotImplemented` return goes straight to `TypeError: unsupported operand type(s)`. The subclass rule needs *different* types, one a proper subclass of the other, before it can fire. ### How CPython decides At the C level the arithmetic dunders of a Python-defined class share a single slot function, so before it swaps the order the interpreter has to check whether the right operand's type genuinely supplies a different reflected method than the left operand's type would — the "overrides" test above. If the left type has no such method at all and the right type does, that also counts as an override. Only then are the operands swapped for the first call. If the reflected call returns `NotImplemented`, the interpreter falls back to the left operand's ordinary method, so the subclass never loses the base's behaviour by declining — it only loses it by returning a wrong answer. ### Why it comes up in interviews The rule is genuinely obscure, so it is rarely a gate. It is asked as a probe: it separates people who have read the data-model chapter and reasoned about operator dispatch from people who have only written `__add__` once. The answer an interviewer is listening for is not the C-level mechanism but the *design* claim — the more specific type gets first refusal, because it is the only one that can have been written with knowledge of the other — plus the discipline that follows from it: return `NotImplemented` from an override whenever you want the base class's behaviour back.

  • Does a subclass that inherits __radd__ without redefining it also get first refusal?
    No. The interpreter checks whether the right operand's type supplies a reflected method that differs from the one the left operand's type would use. A subclass that inherits the base's `__radd__` unchanged fails that check, so the ordinary left-first order applies. If the left type has no reflected method at all while the right type does, that counts as an override and the swap happens.
  • How does a subclass override the reflected method but still get the base class's behaviour in some cases?
    By returning `NotImplemented` from the override. The subclass is called first, but the sentinel puts the interpreter back on the normal path, so `type(left).__add__` runs exactly as it would have without the override. That is the difference between an override that narrows behaviour for a few cases and one that silently pre-empts the base class for every mixed expression.
  • Does the rule apply when both operands are instances of the same class?
    No — the swap needs two different types with a subclass relationship. For two instances of one class Python calls `__add__` once and, if it returns `NotImplemented`, raises TypeError immediately; the reflected method is not consulted, since it would only re-run the same code with the arguments swapped.

It is right of first refusal for the specialist: the newer, more specific type is the only party that could have been told about the older one, so it is asked first — and it can always pass.

saying these in an interview costs you the question

  • Insists the left operand's method is always tried first
  • Thinks any subclass relationship flips the order, override or not
  • Believes an inherited reflected method counts as an override
  • Never returns NotImplemented from an override, silently pre-empting the base
  • Expects the reflected method between two instances of one class
  • Explains the rule as an optimisation rather than a specificity rule

context