How to safely override __init__ or __new__ in Python 2.6 and later

Beginning with Python 2.6, following from bug 1683368, object.__init__ and object.__new__ deprecate the support for arbitrary arguments. The old behavior was deprecated in Python 2.6 and removed in Python 3.3. As a result, any subclass that overrides either of these methods must be aware of the presence or absence of the overridden method in the MRO up to but not including 'object'. I articulated this unexpected behavior in this post, giving a simple trivial example.

If that's confusing, don't fret. The details aren't important, because what I'm presenting here is a technique that's engineered to be safe in all cases without baking in the details of the parent class.

class SomeClass(SomeParentClass):
def __new__(cls, *args, **kwargs):
super_new = super(SomeClass, cls).__new__
if super_new is object.__new__:
return super_new(cls)
return super_new(cls, *args, **kwargs)

def __init__(self, *args, **kwargs):
super_init = super(SomeClass, self).__init__
if super_init.__objclass__ is object:
super_init(*args, **kwargs)
The above example presents a generic, trivial implementation of a subclass of SomeParentClass that overrides both __init__ and __new__. It does not add any custom behavior (as a typical override would), but instead focuses on the technique on passing through the calls of __init__ and __new__ to the parent class in a safe way.

If you're overriding __new__ or __init__, especially in a subclass of a class over which you do not have control over the implementation, it is important that you check that the parent call will not invoke __new__ or __init__ with parameters. Otherwise, you may run into one of the following errors when constructing your subclass:

TypeError: object.__init__ takes no parameters.
TypeError: object.__new__ takes no parameters.

Written on May 28, 2014