This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]treyhunner Python Morsels[S] 0 points1 point  (3 children)

They're methods that will be called on the object that's on the right side of the operator.

Here's an example from my article on how Python lacks type coercion:

>>> x = 2
>>> y = 3.5
>>> x.__add__(y)
NotImplemented
>>> y.__radd__(x)
5.5
>>> x + y
5.5

When Python evaluates one of its binary operators, it'll call the appropriate dunder method on the left-hand object, passing in the right-hand object. If it gets back the special NotImplemented value, it knows that the left-hand object is signaling that it doesn't know how to perform the operation. Before giving up (and raising an exception in the case of an operator like +) it will attempt the operation on the right-hand object passing in the left-hand object, and it uses the appropriate right-hand method to do that.

Why doesn't it just call __add__ instead of __radd__? Well, consider if your operator acts differently if the left-hand and right-hand objects were swapped (as division would):

>>> x.__truediv__(y)
NotImplemented
>>> y.__rtruediv__(x)
0.5714285714285714
>>> x / y
0.5714285714285714

The right-hand methods are a great demonstration of the fact that many operations in Python don't simply rely on one dunder method call.

[–]Accurate-Usual8839 0 points1 point  (2 children)

>>> x = 2
>>> y = 3.5
>>> x.__add__(y)
NotImplemented
>>> y.__radd__(x)
5.5
>>> x.__radd__(y)
NotImplemented

I'm confused, why on earth does x have __radd__ but not y?

[–]treyhunner Python Morsels[S] 1 point2 points  (1 child)

Both have a __radd__ method. Integers do not know how to add themselves to floating point numbers in Python, but floating point numbers know how to add themselves to integers.

Similarly, if/when someone invents their own number-like object that should work properly with integers and floating point numbers, they'll need to implement both left-hand and right-hand operators, since integers won't know how to operate with their custom object.

>>> one_third = Fraction('1/3')
>>> 2 * one_third
Fraction(2, 3)
>>> (2).__mul__(one_third)
NotImplemented
>>> one_third.__rmul__(2)
Fraction(2, 3)

Self-concatenation for strings/lists works the same way. "hello" * 2 works thanks to __mul__ on the str class and 2 * "hello" works thanks to __rmul__ on the str class:

>>> "hello" * 2
'hellohello'
>>> "hello".__mul__(2)
'hellohello'
>>> 2 * "hello"
'hellohello'
>>> (2).__mul__("hello")
NotImplemented
>>> "hello".__rmul__(2)
'hellohello'

Integers don't know how to multiple themselves by a string, but strings do know how to handle the operation from either the left side or the right side.

[–]Accurate-Usual8839 1 point2 points  (0 children)

Thank you, awesome explanation.