Difference between a+b and a.__add__(b)
<p>I am currently trying to understand where the difference between using <code>a+b</code> and <code>a.__add__(b)</code> is when it comes to custom classes. There are numerous websites that say that using the '+'-operator results in using the special method <code>__add__</code> - which is fine so far.</p>

<p>But when i run the following example I get two different results.</p>

<pre><code>class C:  
  def __add__(self, other):
    print("C.__add__", self, other)
    return "result"  
  def __radd__(self, other):
    print("C.__radd__", self, other)    
    return "reversed result"

c = C()
print(1+c)
print()
print(1 .__add__(c))
print(int.__add__(1,c))
</code></pre>

<p>Result:</p>

<pre><code>C.__radd__ &lt;C object at 0x7f60b92e9550&gt; 1
reversed result

NotImplemented
NotImplemented
</code></pre>

<p>Now from what I understood, when executing <code>1+c</code> Python checks/executes the int <code>__add__</code> method - finds that there is no implementation for adding int and C objects - returns NotImplemented - which lets Python know to check object C for <code>__radd__</code> and executes the code within.</p>

<p>Why does <code>1+c</code> result in executing the <code>__radd__</code> code but the other two version are just returning <code>NotImplemented</code> without checking <code>__radd__</code> ??</p>

<p><code>a+b</code> is equivalent to <code>import operator; operator.add(a,b)</code>. It starts by calling <code>a.__add__(b)</code> and then, if necessary, <code>b.__radd__(a)</code>. But <code>ifsubclass(type(b), type(a))</code>, then <code>b.__radd__(a)</code> is called first.</p>

<p>Based on the <a href="https://docs.python.org/3/reference/datamodel.html#special-method-names" rel="nofollow">docs on "special" methods</a>:</p>

<ul>
<li><p>Regarding <a href="https://docs.python.org/3/reference/datamodel.html#object.__add__" rel="nofollow"><code>__add__()</code></a>:</p>

<blockquote>
  <p><code>__add__()</code> is called to implement the binary arithmetic "+" operation. For instance, to evaluate the expression x + y, where x is an instance of a class that has an <code>__add__()</code> method, <code>x.__add__(y)</code> is called. </p>
  
  <p>If one of those methods does not support the operation with the supplied arguments, it should return <strong>NotImplemented</strong>.</p>
</blockquote></li>
<li><p>Regarding <a href="https://docs.python.org/3/reference/datamodel.html#object.__radd__" rel="nofollow"><code>__radd__()</code></a>:</p>

<blockquote>
  <p>These functions are only called if the left operand does not support the corresponding operation and the operands are of different types. For instance, to evaluate the expression x + y, where y is an instance of a class that has an <code>__radd__()</code> method, <code>y.__radd__(x)</code> is called if <code>x.__add__(y)</code> returns NotImplemented.</p>
  
  <p>If the right operandâs type is a subclass of the left operandâs type and that subclass provides the reflected method for the operation, this method will be called before the left operandâs non-reflected method. This behavior allows subclasses to override their ancestorsâ operations.</p>
</blockquote></li>
</ul>

<p><strong>Explanation with the examples based on the behaviour:</strong></p>

<p><strong>Case 1:</strong></p>

<pre><code>&gt;&gt;&gt; print 1+c
('C.__radd__', &lt;__main__.C instance at 0x7ff5631397a0&gt;, 1)
reversed result
</code></pre>

<p>These functions <code>radd</code> are only called if the left operand does not support the corresponding operation and the operands are of different types. In this case, <code>1</code> does not support addition of the class hence, it falls back to the <code>__radd__()</code> function of the <code>C</code> class. In case <code>__radd__</code> was not implement in <code>C()</code> class, it would have fallen back to <code>__add__()</code></p>

<p><strong>Case2:</strong></p>

<pre><code>&gt;&gt;&gt; 1 .__add__(c)
NotImplemented
&gt;&gt;&gt; c .__add__(1)
('C.__add__', &lt;__main__.C instance at 0x7ff563139830&gt;, 1)
'result'
</code></pre>

<p><code>1 .__add__(c)</code> gives <code>NotImplemented</code> as <code>1</code> is of <code>int</code> type and <code>add</code> of <code>int</code> class do not supports <code>add</code> with C class object. But <code>c .__add(1)</code> run because <code>C()</code> class supports that.</p>

<p><strong>Case 3:</strong></p>

<pre><code>&gt;&gt;&gt; int.__add__(1, c)
NotImplemented
&gt;&gt;&gt; C.__add__(c, 1)
('C.__add__', &lt;__main__.C instance at 0x7ff5610add40&gt;, 1)
'result'
</code></pre>

<p>Similar to <code>case 2</code>. But here, the call is made via class with first argument as object of that class. Behaviour would be same.</p>

<p><strong>Case 4:</strong> </p>

<pre><code>&gt;&gt;&gt; int.__add__(c, 1)
Traceback (most recent call last):
  File "&lt;stdin&gt;", line 1, in &lt;module&gt;
TypeError: descriptor '__add__' requires a 'int' object but received a 'instance'
&gt;&gt;&gt; C.__add__(1, c)
Traceback (most recent call last):
  File "&lt;stdin&gt;", line 1, in &lt;module&gt;
TypeError: unbound method __add__() must be called with C instance as first argument (got int instance instead)
</code></pre>

<p>Vice-versa of <code>case 3</code>. As is cleared from the stack-trace, <code>__add__</code> expected the object of the calling class as the first argument, failing which resulted in exception.</p>

python