Creating my own "integer" object in Python

Question:

Essentially I want to be able to do something like:

a = Integer(1)
a += 1
print a

And of course printing the number two as result. What methods do I need to create to get this behaviour in my Integer class?

Disclaimer: I’m not planning to use this for “real”, just curious.

Asked By: Johanna Larsson

||

Answers:

This is a simple and incomplete example. Look at methods __sub__, __div__ and so on.

class Integer(object):
    def __init__(self, val=0):
        self._val = int(val)
    def __add__(self, val):
        if isinstance(val, Integer):
            return Integer(self._val + val._val)
        return self._val + val
    def __iadd__(self, val):
        self._val += val
        return self
    def __str__(self):
        return str(self._val)
    def __repr__(self):
        return 'Integer(%s)' % self._val

Then

n = Integer()
print n
m = Integer(7)
m+=5
print m

EDIT fixed __repr__ and added __iadd__. Thanks to @Keith for pointing problems out.
EDIT Fixed __add__ to allow addition between Integers.

Answered By: juanchopanza

You can use operator overloading:

class Integer:

  def __init__(self, value):
    self.value = value

  def __repr__(self):
    return str(self.value)

  def __add__(self, value):
    self.value += value
    return self

a = Integer(2)
print a

a = a+3
print a

a += 4
print a
Answered By: Howard

I assume you want your Integer class to be mutable. To get your example, this will work:

class Integer(object):
    def __init__(self, num):
        self._val = num

    def __iadd__(self, other):
        self._val += int(other)

    def __str__(self):
        return str(self._val)
Answered By: Keith

First, take a quick look at the documentation in the reference manual on emulating numeric types.

(Don’t get too stuck on that – it’s just to give you some familiarity with the methods underlying arithmetic operations in Python)

Then refer to the documentation for the numbers module, which includes all the Abstract Base Classes that are most relevant to emulating different kinds of numbers (e.g. numbers.Integral for custom integers).

Answered By: ncoghlan

If you want to overload operators of the default cast-to-string method, the phrase you’re looking for is “magic methods”. These are the methods named like “__<name>__” and are used by python in cases other than direct method calls. You would want to define the __add__ and __str__ methods for your class in order for lines 2 and 3, respectively, to work.

Its worth mentioning that the __add__ method will be called if your new type is the left operand, and any type may be passed as its argument. For cases when yours is the right operand, you should also define the __radd__ method. This goes for all of the binary operators.

For a more complete list of magic methods for a numeric type, see Emulating Numeric Types.

Answered By: Aaron Dufour
class Integer(object):

    def __init__(self, value=0):
        self._value = int(value)

    def __add__(self, other):
        if isinstance(other, Integer):
            return Integer(self._value + other._value)
        return Integer(self._value + other)

    def __iadd__(self, other):
        if isinstance(other, Integer):
            self._value += other._value
        else:
            self._value += other
        return self

    def __sub__(self, other):
        if isinstance(other, Integer):
            return Integer(self._value - other._value)
        return Integer(self._value - other)

    def __isub__(self, other):
        if isinstance(other, Integer):
            self._value -= other._value
        else:
            self._value -= other
        return self

    def __mul__(self, other):
        if isinstance(other, Integer):
            return Integer(self._value * other._value)
        return Integer(self._value * other)

    def __div__(self, other):
        if isinstance(other, Integer):
            return Integer(self._value / other._value)
        return Integer(self._value / other)

    def __str__(self):
        return str(self._value)

    def __int__(self):
        return self._value

    def __float__(self):
        return float(self._value)

    def __repr__(self):
        return 'Integer(%s)' % self._value
Answered By: Nikolay

Try this:

class Integer(int):
    def __init__(self, value):
        self.value = value
    # Add extra stuff here.

This will make a class that is based on int, which takes care of the __repr__, __iadd__, and __isub__.

Answered By: Aiden Blishen Cuneo

If you create the class using class Integer(object) Python 3 (I don’t know for Python 2) will not allow you to use your custom integer to access list items, for example. So, class Integer(int) should be used in order to Python allows you to use the custom variable for the same things the standard int is used.

Based on juanchopanza‘s answer, a modification is made to create a custom class inherited from int by using the __new__ method instead of the __init__ method. It’s usefull if you want to pass more arguments than just val during the class instantiation.

class Integer(int):
    def __new__(cls, val):
        instance = super().__new__(cls, val)
        cls._val = val
        # Customize your instance here...
        return instance
    def __add__(self, val):
        if isinstance(val, Integer):
            return Integer(self._val + val._val)
        return Integer(self._val + val)
    def __iadd__(self, val):
        if isinstance(val, Integer):
            return Integer(self._val + val._val)
        return Integer(self._val + val)
    def __str__(self):
        return str(self._val)
    def __repr__(self):
        return 'Integer(%s)' % self._val

Another modification is always return an Integer instance after math operations as __add__ and __iadd__. Otherwise, the result can be a int and the next time you call a math operation, the standard int methods will be called.

Reference about the __new__ method here.

Answered By: FilipeTavares

nobody mentioned it, but since this post is still in top research so i post it even if unnecessary:

do not forget to override index
otherhwise you can’t use your custom number to do things like list[custom_number]

class custom_number:
    def __init__(self, value):
        self.value = value

    def __index__(self):
        return self.value
    ...

foo = custom_number( 1 )
alist = [ 'wrong' , 'right' ]
print( alist[ foo ] )       
>>> 'right'
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.