views:

603

answers:

1

I have a class Parent. I want to define a __new__ for Parent so it does some magic upon instantiation (for why, see footnote). I also want children classes to inherit from this and other classes to get Parent's features. The Parent's __new__ would return an instance of a subclass of the child class's bases and the Parent class.

This is how the child class would be defined:

class Child(Parent, list):
    pass

But now I don't know what __new__ to call in Parent's __new__. If I call object.__new__, the above Child example complains that list.__new__ should be called. But how would Parent know that? I made it work so it loops through all the __bases__, and call each __new__ inside a try: block:

class Parent(object):
    def __new__(cls, *args, **kwargs):
        # There is a special wrapper function for instantiating instances of children
        # classes that passes in a 'bases' argument, which is the __bases__ of the
        # Children class.
        bases = kwargs.get('bases')
        if bases:
            cls = type('name', bases + (cls,), kwargs.get('attr', {}))
            for base in cls.__mro__:
                if base not in (cls, MyMainType):
                    try:
                        obj = base.__new__(cls)
                        break
                    except TypeError:
                        pass
            return obj
        return object.__new__(cls)

But this just looks like a hack. Surely, there must be a better way of doing this?

Thanks.

  • The reason I want to use __new__ is so I can return an object of a subclass that has some dynamic attributes (the magic __int__ attributes, etc) assigned to the class. I could have done this in __init__, but I would not be able to modify self.__class__ in __init__ if the new class has a different internal structure, which is the case here due to multiple inheritance.
+3  A: 

I think this will get you what you want:

return super(Parent, cls).__new__(cls, *args, **kwargs)

and you won't need the bases keyword argument. Unless I'm getting you wrong and you're putting that in there on purpose.

Omnifarious
I think this did it. I tried this before, unfortuantely, I had some other bug in my code that was preventing this from working.The super function is one heck of a magic bullet.
MTsoul
@MTsoul, Indeed it is. To be honest, I don't know why that worked exactly, I just figured it would. :-)
Omnifarious