7

I am developing a simple type system for my own interpreter. I am writing something like this:

class Base(object):
    def __init__(self, content):
        self.__content = content

    @property
    def content(self):
        return self.__content

    @content.setter
    def content(self, value):
        self.__content = value

class Number(Base):
    def __init__(self, content):
        super(Number, self).__init__(content)

    def __add__(self, other):
        return Number(self.content + other.content)

    ...and so on

class Float(Number):
    def __init__(self, content):
        super(Float, self).__init__(content)

class Integer(Number):
    def __init__(self, content):
        super(Integer, self).__init__(content)

My problem is that obviously if I do something like this:

if __name__ == '__main__':
    f1 = Float(3.5)
    f2 = Float(2.3)
    f3 = f1 + f2
    type(f3)

I have summed f1 and f2, which are Float type, but I have obtained f3, which is Number type, but I would like f3 to be a Float type. How could I define my add operator just one time in my Number superclass returning a type which is the same of f1 and f2? Have I to use isinstance? Is there a cleaner way to do this?

Thank you!

JohnQ
  • 1,073
  • 2
  • 10
  • 17

1 Answers1

11

You could do something with __class__:

def __add__(self, other):
    return self.__class__(self.content + other.content)

As, @Eric points out, you may want to do something like

if self.__class__ == other.__class__:
    <use __class__>
else:
    <use Number>

to ensure predicable behaviour (or some other action if the classes don't match).

__radd__ is also worth overriding here:

__radd__ = __add__

which will make Number(1) + Float(1) == Float(1) + Number(1) == Float(2)

huon
  • 94,605
  • 21
  • 231
  • 225
  • You might want to think carefully about whether you want `self.__class__` or `other.__class__` – Eric May 25 '13 at 13:30
  • Oh, thank you. It works perfectly. I thought self.__class__ in the Number class would have been equal to 'Number'... I was wrong. – JohnQ May 25 '13 at 13:44
  • To expand further, I think you want `{(1, 0): self.__class__, (0, 1): other.__class__}.get((issubclass(self.__class__, other.__class__), issubclass(other.__class__, self.__class__)), Number)`. That would be less obtuse if I din't have to fit it in a comment. – Eric May 26 '13 at 09:50
  • 1
    Actually, scrap that. Just alias `__radd__`, and python will take care of things – Eric May 26 '13 at 09:52
  • @Eric, feel free to edit it into my answer since it will be clearer there. – huon May 26 '13 at 10:07