Whenever a superclass implements a __init__ method to initialize its attributes, subclasses derived from it have to invoke the __init__ method of the superclass. This recipe is a different mechanism of initializing the attributes of a superclass with default values, achieved by overriding the __new__ method.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
# Simple inheritance case class super1 (object): def __new__(typ, *args, **kwargs): obj = object.__new__(typ, *args, **kwargs) obj.attr1 =  return obj class derived1(super1): def __init__(self, arg4, **kwargs): self.attr4 = arg4 self.attr5 = kwargs['arg5'] if '__main__'==__name__: d1 = derived1(222, arg5=333) d1.attr1.append(111) print d1.attr1, d1.attr4, d1.attr5, print isinstance(d1, super1) # Multiple inheritance case class super2 (object): def __new__(typ, *args, **kwargs): obj = object.__new__(typ, *args, **kwargs) obj.attr2 = 222 return obj import copy class derived2 (super1, super2): def __new__(typ, *args, **kwargs): objList = [sup.__new__(typ, *args, **kwargs) for sup in derived2.__bases__] for obj in objList[1:]: objList.__dict__.update(copy.deepcopy(obj.__dict__)) objList.attr3 = 333 return objList def __init__(self, arg4, **kwargs): self.attr1.append(111) self.attr4 = arg4 self.attr5 = kwargs['arg5'] if '__main__'==__name__: d1 = derived2(444, arg5=555) print d1.attr1, d1.attr2, d1.attr3, d1.attr4, d1.attr5, print isinstance(d1, super1), print isinstance(d1, super2)
The code shows how to override the __new__ method in order to initialize instance attributes with default values. This may be desirable to ensure that attributes are initialized correctly in subclasses regardless of how the __init__ methods of those subclasses are implemented (e.g., it ensures that the superclasss attributes are initialized before the subclasss attributes). Overriding the __new__ method can be useful also in other cases. This recipe can be seen as a more general mechanism to follow whenever overriding the __new__ method.
Class super1 overrides its __new__ method in order to initialize its attributes with default values. This allows its subclass derived1 to define its own method __init__ without invoking a parent classs __init__ method.
Class super2 is implemented in a similar way, but class derived2 shows how to use such a mechanism in the case of multiple inheritance. Attributes from the superclasses are inherited in this example from left to right, which means that attributes in a superclass can be overridden by attributes in a superclass that succeeds the first one in the inheritance sequence of class derived2. Other implementations can use a different inheritance order by changing the order in the list objList.
One object is created for each superclass, but one of them is chosen to update its own dictionary __dict__ with the entries from all the other objects. Finally, this object is the new object that is returned by the __new__ method.
Using cooperative super call useful. Using super to call next method might be useful in this case. It reduces complexity of the derived __new__ when multiple inheritance is involved. Here is an updated version.
Re: Using cooperative super call useful. I contemplated using super() at some point before submitiing the recipe, but I was not clear yet on the behavior of super and of cooperative classes. I have finally read more on the topic and now I get it. You're right, Shalabh, this is a better solution and it actually makes the recipe kind of trivial.
I am not going to make the changes yet on the recipe and I will wait for a verdict from the editors (i.e., whether they would still be interested in the recipe). If there is still an interest, here is what I suggest.
Shalabh's code would be the preferred solution and should be presented first. That solution depends however on the superclasses to be cooperative classes. I tried it, and if super1 does not invoke super(...), the implementation of derived2 breaks (derived2.attr2 is missing).
My original code can then follow with the argument that it should be used when the superclasses may not be cooperative classes. This second solution offers also more control on the order in which attributes are inherited. A note that should be added is that changing that order may be dangerous however, because the order of inheritance for methods is not changed and a dependence of the methods on the attributes may cause trouble.
Super or no super, still useful. I find this recipe to still be useful and educational even after the addition of the super function. Until now, I have not seen much discussion on the __new__ method. And in this recipe, Dan does a great job of exposing the usefulness of the __new__ method. As a result, I am definitely encouraged to exploit the __new__ method in my Python code. And kudos also to Shalabh as well for his contribution of the super function as well! Thanks!
How about using __new__ to implement singletons?
This example is admittedly crude since it doesn't handle subclassing, and there's probably a better way to check for the existence of the MySingletonInstance symbol, but you get the idea. :)
Just for fun, this second example would be a weird way to implement singletons by returning always the class object instead of new instances. It works only if all your methods are static or class methods, of course.
you could also implement Singleton using new and a class attribute to store the instance:
pretty simple, with no need for odd globals or try/except blocks