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.
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.
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:
return
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