8

There's a class (not created by me, from a 3rd party library) that has no __init__ declared (other than object's __init__), and this is its __new__:

def __new__(cls, uid):
    self = super().__new__(cls, uid)
    self._info = get_info_from_uid(uid)
    return self

I can't see why didn't they just use __init__ here, but they didn't.

Now I'd like to subclass this and give it an additional attribute; before I checked the source-code of the class (only the documentation), I thought it's just using __init__ like others, so here's what I did:

class MyClass(TheirClass):
    def __init__(self, uid, my_stuff=()):
        super().__init__(uid)
        self.my_stuff = my_stuff

Apparently this raised a TypeError from object.__init__() not taking parameteres. How should I subclass such class with __new__? Do I just override the __new__ method to?

Markus Meskanen
  • 19,939
  • 18
  • 80
  • 119
  • The `__new__` method, as posted, will not work unless the class inherits from something other than `object` itself; `object.__new__` doesn't take arguments in this case. I'd expect it to read `self = super().__new__(cls)`. – Martijn Pieters Jan 30 '15 at 13:17
  • Also, surely they'd use `get_info_from_uid(uid)` (not `self.uid`) there? – Martijn Pieters Jan 30 '15 at 13:19
  • @MartijnPieters Yeah it does inherit from few other classes too, but they don't have `__init__` declared either. And yeah sorry about the `self.uid`, that was my typo when trying to create my own class, forgot it there. – Markus Meskanen Jan 30 '15 at 13:43

1 Answers1

12

Since the original project stuck with __new__ and using both __init__ and __new__ together in sub-classes can get very tricky indeed, you'll have to use __new__ in subclasses as well:

class MyClass(TheirClass):
    def __new__(cls, uid, my_stuff=()):
        self = super().__new__(cls, uid)
        self.my_stuff = my_stuff
        return self

Perhaps the original author felt that the type should be treated as an immutable.

You can still use __init__ if you insist, but you'll have to specify a __new__ method anyway to account for the extra argument your __init__ now takes:

class MyClass(TheirClass):
    def __new__(cls, uid, *args):
        # ignore the extra arguments
        return super().__new__(cls, uid)

    def __init__(self, uid, my_stuff=()):
        self.my_stuff = my_stuff
Community
  • 1
  • 1
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • 3
    "Perhaps the original author felt that the type should be treated as an immutable.", can you enlighten me a little on this? How's the `__new__` related to making an object immutable? Edit: Yeah thanks, I'll just override the `__new__` in my subclass! :) – Markus Meskanen Jan 30 '15 at 13:44