3

I'd like to know how inheritance works for int, list, string and other immutable types.

Basically I'd just inherit a class like this:

class MyInt(int):
    def __init__(self, value):
        ?!?!?

I can't seem to figure out, how do I set the value like it's set for int? If I do self.value = value then my class will be used like this:

mi = MyInt(5)
print(mi.value) # prints 5

Whereas I want to use it like this:

mi = MyInt(5)
print(mi) # prints 5

How do I do this?

Patrik Lippojoki
  • 1,603
  • 4
  • 19
  • 22

1 Answers1

8

You can subclass int, but because it is immutable you need to provide a .__new__() constructor hook:

class MyInt(int):
    def __new__(cls, value):
        new_myint = super(MyInt, cls).__new__(cls, value)
        return new_myint

You do need to call the base __new__ constructor to get your subclass properly created.

In Python 3, you can omit the arguments to super() altogether:

class MyInt(int):
    def __new__(cls, value):
        new_myint = super().__new__(cls, value)
        return new_myint

Of course, this assumes you wanted to manipulate value before passing in to super().__new__() or manipulate new_myint some more before returning; otherwise you may as well remove the whole __new__ method and just implement this as class MyInt(int): pass.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • Alright, that's more complicated than I thought. But I do understand what it does tho. For python 3, can't I just use `super()` instead of `super(MyInt, cls)`? Also can I still create methods and/or other attributes for this? – Patrik Lippojoki Feb 26 '13 at 09:55
  • That inner `__new__` call should be `__new__(cls, value)`. – poke Feb 26 '13 at 09:55
  • @PatrikLippojoki Yes, just `super()` should work fine. And custom methods work just as you expect. Just note that the actual int value is accessible through just `self` within the methods. – poke Feb 26 '13 at 09:56
  • @PatrikLippojoki: Yes, for Python 3 you can omit the arguments. – Martijn Pieters Feb 26 '13 at 09:58
  • @poke: yeah, it's a static method, not a class method, as it turns out. :-P – Martijn Pieters Feb 26 '13 at 09:58
  • Thanks, I'll accept asap ! :) – Patrik Lippojoki Feb 26 '13 at 10:00
  • just curious, is there a reason to use cls over self? – monkut Feb 26 '13 at 10:02
  • 2
    Oh btw., I think this is worth noting, you *only* need to override the class constructor `__new__`, if you actually want to do something special on construction (like initializing other properties etc.). But if you don’t, you can just leave it out and it will work. So `class MyInt(int): pass` would be a perfect subtype. – poke Feb 26 '13 at 10:03
  • 1
    @monkut As far as I understand, when you call `__new__` the object is not constructed yet, so there is no such thing as `self` (the object doesn't exist). `cls` means the class itself, so we're constructing a new instance of that class. – Patrik Lippojoki Feb 26 '13 at 10:04
  • 1
    @monkut That is just a convention to make it clear that it is *not* an instance method. The value that is passed in is actually the type, i.e. a reference to `MyInt`, while `self` would represent an actual object of said type. The object is only being created during the `__new__`. – poke Feb 26 '13 at 10:05
  • I don't think it's necessary to implement `__new__` in this case. Actually, `MyInt` with this kind of overridden `__new__` is almost equivalent to `class MyInt(int): pass` – nymk Feb 26 '13 at 10:08
  • @poke: That was implicit; made it explicit now. – Martijn Pieters Feb 26 '13 at 10:11