1

Is it possible to define a data object in python that behaves like a normal integer when used in mathematical operations or comparisons, but is also able to store instance variables?

In other words, it should be possible to do the following things:

pseudo_integer = PseudoInteger(5, hidden_object="Hello World!")
print(5 + pseudo_integer) # Prints "10"
print(pseudo_integer == 5) # Prints "True"
print(pseudo_integer.hidden_object) # Prints "Hello World!"
  • have you already tried smth? please post your tries here – messerbill Jan 26 '18 at 16:03
  • So what would you expect the `hidden_object` to be, after a addition ? – llllllllll Jan 26 '18 at 16:03
  • @messerbill: I wouldn't know how to tackle the problem so I haven't tried anything. –  Jan 26 '18 at 16:10
  • @liliscent: There is no need to call `hidden_object` after an addition, so it's okay if it's gone. I just need it to either be able to be added, compared or `hidden_object` to be obtained. –  Jan 26 '18 at 16:12
  • What type do you want `5 + pseudo_integer` to have? Should it have type `int`, or type `PseudoInteger`? What about `pseudo_integer + pseudo_integer`? – Mark Dickinson Jan 26 '18 at 16:59

4 Answers4

3

So, all answers above are fine, but probably you don't want to re-define all existing methods.

Normally, in python you can just subclass any built-in class (type). But with immutable types (and integers in python are immutable) is slightly tricky. TL;DR:

class PseudoInt(int):
    def __new__(cls, x, hidden, *args, **kwargs):
        instance = int.__new__(cls, x, *args, **kwargs)
        instance.hidden = hidden
        return instance

x = PseudoInt(5, 'secret')
x.hidden  # 'secret'
x + 4  # 9
x * 3  # 15

Normally, you should reload __init__ method, but with immutable bases you should use __new__. You can read more about data model in corresponding docs section

All this is viable only if you need single signature for constructing your object. If its fine to have 1 call for creating, and dedicated calls to populate object with attributes - Kevin's answer is all you need

Slam
  • 8,112
  • 1
  • 36
  • 44
  • 1
    The OP will still have to override existing methods like `__add__` if they want the result of `PseudoInt(5) + 3` to be a `PseudoInt`. – Mark Dickinson Jan 26 '18 at 17:01
  • True. The same applies to in-place math, like `PseudoInt(5) += 4` will return 9. But I guess, this is what OP wanted - int-like object. To return same class with math ops, __ methods should be reloaded, you're right. – Slam Jan 26 '18 at 17:06
  • 2
    I'd hope that `PseudoInt(5) += 4` would be a `SyntaxError`! `` – Mark Dickinson Jan 26 '18 at 17:07
1

You simply need a class for this:

class PseudoInteger(object):
    def __init__(self, num, hidden=None):
        self.num = num
        self.hidden = hidden

    def __add__(self,  otherVal):
        if isinstance(otherVal, PseudoInteger):
            return self.num + otherVal.num
        else:
            return self.num + otherVal

p = PseudoInteger(4, 'Tiger')
q = PseudoInteger(6, 'lion')

print (p+q)
print (p+4)

This prints out:

10
8

You have to add the other operations (division, substraction, eq, ...) you need to the class on your own :)

Maurice Meyer
  • 17,279
  • 4
  • 30
  • 47
  • Hi, thank you very much, this looks promising. i have one question: is this also possible without manually having to define all these methods, like add , sub, eq, gt etc? So basically that it inherits all these methods from the "original" Integer class and I just add the instance variables and methods that I need to it? –  Jan 26 '18 at 16:28
  • No, [https://stackoverflow.com/questions/3238350/subclassing-int-in-python](https://stackoverflow.com/a/3238445/7216865) – Maurice Meyer Jan 26 '18 at 16:38
  • 3
    @MauriceMeyer, you're actually pointing to the post that shows _how to do this_, not why it's impossible ;) – Slam Jan 26 '18 at 16:49
1

Yes, it is. You can create your own custom class. Python has many magic methods to help you archive that.

Check the code:

class PseudoInteger:
    def __init__(self, x, s):
        self.x = x
        self.s = s

    def __add__(self, num):
        return self.x + num

    def __eq__(self, num):
        return self.x == num


a = PseudoInteger(5, 'hello, world')
print(a + 3)
print(a == 5)
print(a == 2)

Or you can just inherit from int, after creating an instance, you are able to assign attributes to the inherited int object. You can't assign attributes to int directly, because int does not support item assignment :

class PseudoInteger(int):
    pass

a = PseudoInteger(5)
a.hidden = 'hello, world'

print(a)
print(a == 5)
print(a + 3)
print(a.hidden)
Kevin
  • 483
  • 3
  • 12
0

Look into implementing the __add__ and __eq__ methods for your PseudoInteger class

David
  • 413
  • 6
  • 13