The arithmetic operator's special methods

There are a total of 13 binary operators and their associated special methods. We'll focus on the obvious arithmetic operators first. The special method names match the operators (and functions), as shown in the following table:

Method

Operator

object.__add__(self, other)

+

object.__sub__(self, other)

-

object.__mul__(self, other)

*

object.__truediv__(self, other)

/

object.__floordiv__(self, other)

//

object.__mod__(self, other)

%

object.__divmod__(self, other)

divmod()

object.__pow__(self, other[, modulo])

pow() as well as **

 

And yes, interestingly, two functions are included with the various symbolic operators. There are a number of unary operators and functions, which have special method names as shown in the following table:

Method

Operator

object.__neg__(self)

-

object.__pos__(self)

+

object.__abs__(self)

abs()

object.__complex__(self)

complex()

object.__int__(self)

int()

object.__float__(self)

float()

object.__round__(self[, n])

round()

object.__trunc__(self[, n])

math.trunc()

object.__ceil__(self[, n])

math.ceil()

object.__floor__(self[, n])

math.floor()

 

And yes, there are a lot of functions in this list, too. We can tinker with Python's internal trace to see what's going on under the hood. We'll define a simplistic trace function that will provide us with a little bit of visibility into what's going on:

def trace(frame, event, arg): 
    if frame.f_code.co_name.startswith("__"): 
        print(frame.f_code.co_name, frame.f_code.co_filename, event) 

This function will dump special method names when the code associated with the traced frame has a name that starts with "__". We can install this trace function in Python using the following code:

import sys 
sys.settrace(trace) 

Once installed, everything passes through our trace() function. We're filtering the trace events for special method names. We'll define a subclass of a built-in class so that we can explore the method resolution rules:

class noisyfloat( float ): 
    def __add__( self, other ): 
        print( self, "+", other ) 
        return super().__add__( other ) 
    def __radd__( self, other ): 
        print( self, "r+", other ) 
        return super().__radd__( other ) 

This class overrides just two of the operator's special method names. When we add noisyfloat values, we'll see a printed summary of the operation. Plus, the trace will tell us what's going on. The following is the interaction that shows Python's choice of class to implement a given operation:

>>> x = noisyfloat(2) 
>>> x+3 
__add__ <stdin> call 
2.0 + 3 
5.0 
>>> 2+x 
__radd__ <stdin> call 
2.0 r+ 2 
4.0 
>>> x+2.3 
__add__ <stdin> call 
2.0 + 2.3 
4.3 
>>> 2.3+x 
__radd__ <stdin> call 
2.0 r+ 2.3 
4.3 

From x+3, we see how noisyfloat+int provided the int object, 3, to the __add__() method. This value was passed to the superclass, float, which handled the coercion of 3 to a float and did the addition, too. 2+x shows how the right-hand side noisyfloat version of the operation was used. Again, int was passed to the superclass that handled the coercion to float. From x+2.3, we come to know that noisyfloat+float used the subclass that was on the left-hand side. On the other hand, 2.3+x shows how float+noisyfloat used the subclass on the right-hand side and the reflected __radd__() operator.

Let's see how to create a numeric class.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset