Skip to content Skip to sidebar Skip to footer

Overload All Arithmetic Operators In Python

Suppose I build a class that basically represents a number plus some fancy stuff. Instances of that class should behave like numbers in any arithmetic/mathematical operation. I cou

Solution 1:

What about this?

class MyFancyNumber(int):
    def __new__(cls, num, info=None):
        return super(MyFancyNumber, cls).__new__(cls, num)
    def __init__(self, num, info=None):
        self.num = num
        self.info = info
>>> MyFancyNumber(5)
5
>>> MyFancyNumber(5) + 2
7
>>> MyFancyNumber(5) / 4
1
>>> MyFancyNumber(5) * 0.5
2.5
>>> MyFancyNumber(5) - 7
-2
>>> MyFancyNumber(5, 'info').info
'info'

I guess based on the above, you can figure out what you need.


Solution 2:

I don't endorse this as being particularly idiomatic, but...

Assuming all of your function definitions behave identically, like "just invoke the base behavior of the self.num class and apply all the non-self arguments to it", then you can loop through all the function names you want to define, and create each one using setattr. Example:

class MyFancyNumber(object):
    def __init__(self, num, info):
        self.num = num
        self.info = info
    def __repr__(self):
        return "MyFancyNumber({}, {})".format(repr(self.num), repr(self.info))

def make_func(name):
    return lambda self, *args: MyFancyNumber(getattr(self.num, name)(*args), self.info)

for name in ["__add__", "__sub__", "__mul__", "__div__", "__invert__", "__neg__", "__pos__"]:
    setattr(MyFancyNumber, name, make_func(name))

x = MyFancyNumber(50, "hello")
print(x + 10)
print(x - 10)
print(x * 10)
print(x / 10)
print(~x)
print(-x)
print(+x)

Result:

MyFancyNumber(60, 'hello')
MyFancyNumber(40, 'hello')
MyFancyNumber(500, 'hello')
MyFancyNumber(5, 'hello')
MyFancyNumber(-51, 'hello')
MyFancyNumber(-50, 'hello')
MyFancyNumber(50, 'hello')

Edit: I wasn't sure whether you wanted the result of arithmetic to be a MyFancyNumber or a regular built-in numerical type, but either way, the implementation is pretty similar:

class MyFancyNumber(object):
    def __init__(self, num, info):
        self.num = num
        self.info = info
    def __repr__(self):
        return "MyFancyNumber({}, {})".format(repr(self.num), repr(self.info))

def make_func(name):
    return lambda self, *args: getattr(self.num, name)(*args)

for name in ["__add__", "__sub__", "__mul__", "__div__", "__invert__", "__neg__", "__pos__"]:
    setattr(MyFancyNumber, name, make_func(name))

x = MyFancyNumber(50, "hello")
print(x + 10)
print(x - 10)
print(x * 10)
print(x / 10)
print(~x)
print(-x)
print(+x)

Result:

60
40
500
5
-51
-50
50

Solution 3:

No, you have to define all the arithmetic operators otherwise how would Python know what to do with them. Don't forget you also need the reverse operators like __radd__.

Also the code you've written returns an int for x+1. Did you mean that or did you want adding a fancy number to return another fancy number?

You could just subclass int or float. Then you don't have to reimplement the operators but you'll still lose the special nature whenever you operate on a value.

A better solution would just be to have the numeric value in an attribute and convert to numbers explicitly when that's what you want. You can use __int__() and __float__() to implement the conversion.

The documentation covers what you need to do if you really do want to emulate a numeric type: for Python 3.x https://docs.python.org/3/reference/datamodel.html?highlight=int#emulating-numeric-types or for Python 2.x https://docs.python.org/2/reference/datamodel.html?highlight=int#emulating-numeric-types


Solution 4:

This works for me in python 2.7 as long as you pass just one argument in the init. Sadly have no idea why it works though.

class MyFancyNumber(int):
    def __init__(self, num):
        self.num = num # the actual number

    def add_info(self,info):
        self.info = info  ## Add the info separately

    def doFancyStuff(self):
        # does something fancy

print MyFancyNumber(5)+5    

Usage

f = MyFancyNumber(2)
f.add_info(info)
f+4               ## returns 6

Post a Comment for "Overload All Arithmetic Operators In Python"