Yes, the next level of complexity is that `a + b` will sometimes fall back to `b.__radd__(a)` if `a.__add__(b)` returns `NotImplemented`. But also:
- There are situations where `__radd__` takes priority over `__add__`. The rules for determining that priority are complex (and IIRC subtly different from the rules that determine whether `a < b` prioritises `a.__lt__(b)` or `b.__gt__(a)`).
- The lookup of `__add__` etc uses a special form of attribute lookup that's neither equivalent to `a.__add__` nor `type(a).__add__`. This special lookup only searches `type(a)` whereas the first would find an `__add__` function on `a`, and the second on `type(type(a))`.