I am trying to overload the division operator in python.
class Fraction:
def __init__(self,top,bottom):
def gcd(m, n):
while m % n != 0:
old_m = m
old_n = n
m = old_n
n = old_m % old_n
return n
common = gcd(top,bottom)
self.num = top/common
self.den = bottom/common
def __str__ (self):
return str(self.num) + "/" + str(self.den)
def get_num(self):
return self.num
def get_den(self):
return self.den
def __add__(self, other_fraction):
new_num = self.num * other_fraction.den + self.den * other_fraction.num
new_den = self.den * other_fraction.den
return Fraction(new_num, new_den)
def __sub__(self, other_fraction):
new_num = self.num * other_fraction.den - self.den * other_fraction.num
new_den = self.den * other_fraction.den
return Fraction(new_num, new_den)
def __mul__ (self, other_fraction):
new_num = self.num * other_fraction.num
new_den = self.den * other_fraction.den
return Fraction(new_num, new_den)
def __truediv__(self, other_fraction):
new_num = self.num * other_fraction.den
new_den = self.den * other_fraction.num
return Fraction(new_num, new_den)
def __eq__(self, other):
first_num = self.num * other.den
second_num = other.num * self.den
return first_num == second_num
a = Fraction(10,20)
b = Fraction(30,20)
print a
print "numerator is",a.get_num()
print "denominator is",a.get_den()
print "equality is",(a==b)
print "sum is",(a+b)
print "difference is",(a-b)
print "product is",(a*b)
print "division is",(a/b)
But I get an error at __truediv__
:
TypeError: unsupported operand type(s) for /: 'instance' and 'instance'
What is wrong with the code?
The Python __truediv__() method is called to implement the normal division operation / called true division—as opposed to the floor division operation // . For example to evaluate the expression x / y , Python attempts to call x. __truediv__(y) .
Operator Overloading means giving extended meaning beyond their predefined operational meaning. For example operator + is used to add two integers as well as join two strings and merge two lists. It is achievable because '+' operator is overloaded by int class and str class.
For example, the + operator will perform arithmetic addition on two numbers, merge two lists, or concatenate two strings. This feature in Python that allows the same operator to have different meaning according to the context is called operator overloading.
I understand that __sub__ is an operator overloader in python and intercepts the p1-p2 call.
From the docs:
object.__div__(self, other) object.__truediv__(self, other)
The division operator (/) is implemented by these methods. The
__truediv__()
method is used when__future__.division
is in effect, otherwise__div__()
is used. If only one of these two methods is defined, the object will not support division in the alternate context; TypeError will be raised instead.
And here:
A future statement is a directive to the compiler that a particular [python program] should be compiled using syntax or semantics that will be available in a ... future release of Python. The future statement is intended to ease migration to future versions of Python that introduce incompatible changes to the language. It allows use of the new features before the release in which the feature becomes standard.
future_statement: from __future__ import feature
The features recognized by Python 2.x are unicode_literals, print_function, absolute_import, division, generators, nested_scopes and with_statement
Now, some tests:
~$ python2.7
Python 2.7.6 (v2.7.6:3a1db0d2747e, Nov 10 2013, 00:42:54)
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> 3/2
1
>>> exit()
~$ python3.2
Python 3.2.3 (v3.2.3:3d0686d90f55, Apr 10 2012, 11:25:50)
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> 3/2
1.5
So, you see, the effect of the /
operator changed in python 3.x. You can see that in the example below, as well:
class Dog(object):
def __div__(self, other):
print("__div__ called")
def __truediv__(self, other):
print("__truediv__ called")
Dog() / Dog()
--output:--
~/python_programs$ python2.7 myprog.py
__div__ called
~/python_programs$ python3.4 myprog.py
__truediv__ called
Because __truediv__
is not called by the /
operator in python 2.x, overriding __truediv__
in python 2.x has no effect.
PEP 238 - PEP 238 -- Changing the Division Operator
We propose the following transitional measures:
- Classic division will remain the default in the Python 2.x
series; true division will be standard in Python 3.0.
- The // operator will be available to request floor[, i.e. integer,]
division unambiguously.
- The future division statement, spelled "from __future__ import
division", will change the / operator to mean true division
throughout the [program]
Now, look what happens here:
from __future__ import division
class Dog(object):
def __div__(self, other):
print("__div__ called")
def __truediv__(self, other):
print("__truediv__ called")
Dog() / Dog()
--output:--
~/python_programs$ python2.7 myprog.py
__truediv__ called
~/python_programs$ python3.4 myprog.py
__truediv__ called
Now, you get the python3.x effect for the /
operator in python 2.x. So, now you can override __truediv__
to make the /
operator do what you want.
Note that if you want integer division in python 3.x, i.e. 3/2 => 1
, then you have to use the //
operator, which is implemented by __floordiv__
. Likewise, if you do from __future__ import division
in python 2.x, then to get integer division, you have to use the //
operator; and if you want to override the //
operator in a class, you need to implement __floordiv__
.
The object.__truediv__()
special method is only used with the /
operator and then only if you have switched the Python compiler to use true division with:
from __future__ import division
If you did not use that import, the /
operator calls the object.__div__()
special method if present.
The //
operator on the other hand calls the object.__floordiv__()
special method, which you did not implement.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With