On-line Guides
All Guides
eBook Store
iOS / Android
Linux for Beginners
Office Productivity
Linux Installation
Linux Security
Linux Utilities
Linux Virtualization
Linux Kernel
Programming
Scripting Languages
Development Tools
Web Development
GUI Toolkits/Desktop
Databases
Mail Systems
openSolaris
Eclipse Documentation
Techotopia.com
Virtuatopia.com

How To Guides
Virtualization
Linux Security
Linux Filesystems
Web Servers
Graphics & Desktop
PC Hardware
Windows
Problem Solutions

## Numeric Type Special Methods

When creating a new numeric data type, you must provide definitions for the essential mathematical and logical operators. When we write an expression using the usual +, -, *, and /, Python transforms this to method function calls. Consider the following:

```v1= MyClass(10,20)
v2= MyClass(20,40)
x = v1 + v2
```

In this case, Python will evaluate line 3 as if you had written:

```x = v1.__add__( v2 )
```

Every arithmetic operator is transformed into a method function call. By defining the numeric special methods, your class willwork with the built-in arithmetic operators. There are, however, some subtleties to this.

Forward, Reverse and In-Place Method Functions. First, there are as many as three variant methods required to implement each operation. For example, * is implemented by `__mul__`, `__rmul__` and `__imul__`. There are forward and reverse special methods so that you can assure that your operator is properly commutative. There is an in-place special method so that you can implement augmented assignment efficiently (see the section called “Augmented Assignment”).

You don't need to implement all three versions. If you implement just the forward version, and your program does nothing too odd or unusual, everything will work out well. The reverse name is used for special situations that involve objects of multiple classes.

Python makes two attempts to locate an appropriate method function for an operator. First, it tries a class based on the left-hand operand using the "forward" name. If no suitable special method is found, it tries the the right-hand operand, using the "reverse" name.

Consider the following:

```v1= MyClass(10,20)
x = v1 * 14
y = 28 * v1
```

Both lines 2 and 3 require conversions between the built-in integer type and `MyClass`. For line 2, the forward name is used. The expression `v1*14` is evaluated as if it was

```x = v1.__mul__( 14 )
```

For line 3, the reverse name is used. The expression `28*v1` is evaluated as if it was

```y = v1.__rmul__( 28 )
```

The Operator Algorithm. The algorithm for determing what happens with `x` op `y` is approximately as follows. Historically, as Python has evolved, so have the ins and outs of argument coercion. In the future, beginning with Python 3.0, the older notion of type coercion and the `coerce` function will be dropped altogether, so we'll focus on the enduring features that will be preserved. Section 3.4.8 of the Python Language Reference covers this in more detail; along with the caveat that the rules have gotten too complex.

Note than a special method function can return the value `NotImplemented`. This indicates that the operation can't work directly only the values, and another operation should be chosen. The rules provide for a number of alternative operations, this allows a class to be designed in a way that will cooperate successfully with potential future subclasses.

1. The expression `string` % `anything` is a special case and is handled first. This assures us that the value of `anything` is left untouched by any other rules. Generally, it is a tuple or a dictionary, and should be left as such.

2. If this is an augmented assignment statement (known as an in-place operator, e.g., `a` += `b` ) where the left operand implements `__iop__`, then the `__iop__` special method is invoked without any coercion. These in-place operators permit you to do an efficient udpate the left operand object instead of creating a new object.

3. As a special case, if an operator's left operand is an object of a superclass of the right operand's class, the right operand's `__rop__` (subclass) method is tried first. If this is not implemented or returns `NotImplemented`, then the the left operand's `__op__` (superclass) method is used. This is done so that a subclass can completely override binary operators, even for built-in types.

4. Generally, `x.__op__`( `y` ) is tried first. If this is not implemented or returns `NotImplemented`, `y.__rop__`( `x` ) is tried second. In the case of

The following functions are the “forward” operations, used to implement the associated expressions.

method function original expression
`__add__`( `self` , `other` ) `self` + `other`
`__sub__`( `self` , `other` ) `self` - `other`
`__mul__`( `self` , `other` ) `self` * `other`
`__div__`( `self` , `other` ) `self` / `other`
`__mod__`( `self` , `other` ) `self` % `other`
`__divmod__`( `self` , `other` ) `divmod `( `self` , `other` )
`__pow__`( `self` , `other` , [ `modulo` ] ) `self` ** `other` or ```pow ```( `self` , `other` , [ `modulo` ] )
`__lshift__`( `self` , `other` ) `self` << `other`
`__rshift__`( `self` , `other` ) `self` >> `other`
`__and__`( `self` , `other` ) `self` and `other`
`__xor__`( `self` , `other` ) `self` xor `other`
`__or__`( `self` , `other` ) `self` or `other`

The method functions in this group are used to resolve operators using by attempting them using a reversed sense.

method function original expression
`__radd__`( `self` , `other` ) `other` + `self`
`__rsub__`( `self` , `other` ) `other` - `self`
`__rmul__`( `self` , `other` ) `other` * `self`
`__rdiv__`( `self` , `other` ) `other` / `self`
`__rmod__`( `self` , `other` ) `other` % `self`
`__rdivmod__`( `self` , `other` ) `divmod `( `other` , `self` )
`__rpow__`( `self` , `other` ) `other` ** `self` or ```pow ```( `other` , `self` )
`__rlshift__`( `self` , `other` ) `other` << `self`
`__rrshift__`( `self` , `other` ) `other` >> `self`
`__rand__`( `self` , `other` ) `other` and `self`
`__rxor__`( `self` , `other` ) `other` xor `self`
`__ror__`( `self` , `other` ) `other` or `self`

The method functions in the following group implement the basic unary operators.

method function original expression
`__neg__`( `self` ) - `self`
`__pos__`( `self` ) + `self`
`__abs__`( `self` ) `abs `( `self` )
`__invert__`( `self` ) ~ `self`
`__complex__`( `self` ) ```complex ```( `self` )
`__int__`( `self` ) `int `( `self` )
`__long__`( `self` ) `long `( `self` )
`__float__`( `self` ) `float `( `self` )
`__oct__`( `self` ) `oct `( `self` )
`__hex__`( `self` ) `hex `( `self` )

Rational Number Example. Consider a small example of a number-like class. The the section called “Rational Numbers” exercise in Chapter 21, Classes describes the basic structure of a class to handle rational math, where every number is represented as a fraction. We'll add some of the special methods required to make this a proper numeric type. We'll finish this in the exercises.

```class Rational( object ):
def __init__( self, num, denom= 1L ):
self.n= long(num)
self.d= long(denom)
def __add__( self, other ):
return Rational( self.n*other.d + other.n*self.d,
self.d*other.d )
def __str__( self ):
return "%d/%d" % ( self.n, self.d )
```

This class has enough methods defined to allow us to add fractions as follows:

````>>> `

`x = Rational( 3, 4 )`

`>>> `

`y = Rational( 1, 3 )`

`>>> `

`print x+y`

`7/12`
`>>> `
```

In order to complete this class, we would need to provide most of the rest of the basic special method names (there is no need to provide a definition for `__del__`). We would also complete the numeric special method names.

Additionally, we would have to provide correct algorithms that reduced fractions, plus an additional conversion to respond with a mixed number instead of an improper fraction. We'll revisit this in the exercises.

Conversions From Other Types. For your class to be used successfully, your new numeric type should work in conjunction with existing Python types. You will need to use the `isinstance` function to examine the arguments and make appropriate conversions.

Consider the following expressions:

```x = Rational( 22, 7 )
y = x+3
z = x+0.5
```

Variables `y` and `z` should be created as `Rational` fractions. However, our initial `__add__` function assumed that the `other` object is a `Rational` object. Generally, numeric classes must be implemented with tests for various other data types and appropriate conversions.

We have to use the `isinstance` function to perform checks like the following: ```isinstance( other, int )```. This allows us to detect the various Python built-in types.

If the result of `isinstance`( `other` , `factory` ) is true in any of the following cases, some type of simple conversion should be done, if possible.

• isinstance( other, complex ). You may want to raise an exception here, since it's hard to see how to make rational fractions and complex numbers conformable. If this is a common situation in your application, you might need to write an even more sophisticated class that implements complex numbers as a kind of rational fraction. Another choice is to write a version of the `abs` function of the complex number, which creates a proper rational fraction for the complex magnitude of the given value.

• isinstance( other, float ). One choice is to truncate the value of `other` to `long`, using the built-in `long` function and treat it as a whole number, the other choice is to determine a fraction that approximates the floating point value.

• isinstance( other, (int,long) ). Any of these means that the `other` value is clearly the numerator of a fraction, with a denominator of 1.

• isinstance( other, str ) or isinstance( other, unicode ) or isinstance( other, basestring ). Any of these might convert the `other` value to a `long` using the built-in `long` function. If the conversion fails, an exception will be thrown, which will make the error obvious. The `basestring` type, by the way, is the superclass for ASCII strings (`str`) and Unicode strings (`unicode`).

• isinstance( other, Rational ). This indicates that the `other` value is an instance of our `Rational` class; we can do the processing as expected, knowing that the object has all the methods and attributes we need.

Here is a version of `__sub__` with an example of type checking. If the `other` argument is an instance of the class `Rational`, we can perform the subtract operation. Otherwise, we attempt to convert the `other` argument to an instance of `Rational` and attempt the subtraction between two `Rational`s.

```def __sub__( self, other ):
if isinstance(other,Rational):
return Rational( self.n*other.d - other.n*self.d,
self.d*other.d )
else:
return self - Rational(long(other))
```

An alternative to the last line of code is the following.

```        return Rational( self.n-long(other)*self.d, self.d )
```

While this second version performs somewhat quicker, it expresses the basic rational addition algorithm twice, once in the if: suite and again in the else: suite. A principle of object oriented programming is to maximize reuse and minimize restating an algorithm. My preference is to state the algorithm exactly once and reuse it as much as possible.

Reverse Operators. In many cases, Python will reverse the two operands, and use a function like `__rsub__` or `__rdiv__`. For example:

```def __rsub__( self, other ):
if isinstance(other,Rational):
return Rational( other.n*self.d - self.n*other.d,
self.d*other.d )
else:
return Rational(long(other)) - self
```

You can explore this behavior with short test programs like the following:

```x = Rational( 3,4 )
print x-5
print 5-x
```

 Published under the terms of the Open Publication License Design by Interspire