I'm interested in using the __new__
functionality to inject code into the __init__
function of subclasses. My understanding from the documentation is that python will call __init__
on the instance returned by __new__
. However, my efforts to change the value of __init__
in the instance before returning it from __new__
don't seem to work.
class Parent(object):
def __new__(cls, *args, **kwargs):
new_object = super(Parent, cls).__new__(cls)
user_init = new_object.__init__
def __init__(self, *args, **kwargs):
print("New __init__ called")
user_init(self, *args, **kwargs)
self.extra()
print("Replacing __init__")
setattr(new_object, '__init__', __init__)
return new_object
def extra(self):
print("Extra called")
class Child(Parent):
def __init__(self):
print("Original __init__ called")
super(Child, self).__init__()
c = Child()
The above code prints:
Replacing __init__
Original __init__ called
but I would expect it to print
Replacing __init__
New __init__ called
Original __init__ called
Extra called
Why not?
I feel like Python is calling the original value of __init__
, regardless of what I set it to in __new__
. Running introspection on c.__init__
shows that the new version is in place, but it hasn't been called as part of the object creation.
__init__ method calls overridden method When an instance of a class is initialized, the super-class state should be fully initialized before it becomes visible to the subclass. Calling methods of the subclass in the superclass' __init__ method violates this important invariant.
__new__ is static class method, while __init__ is instance method. __new__ has to create the instance first, so __init__ can initialize it. Note that __init__ takes self as parameter. Until you create instance there is no self . Now, I gather, that you're trying to implement singleton pattern in Python.
Overriding init()Override the class initializer init() to initialize or allocate resources for the servlet instance's life, such as a counter. The init() method runs after the servlet is instantiated but before it accepts any requests.
Constructor Overriding Example We created an object for the child class. When the object is created, it will call child class constructor. If we want to call the base class constructor and initialize the variable instvar. we use super() function.
Well, the new object is expected to be empty before the __init__
is called. So probably python, as optimization, does not bother to query the object and goes to fetch __init__
straight from the class.
Therefore you'll have to modify __init__
of the subclasses themselves. Fortunately Python has a tool for that, metaclasses.
In Python 2, you set metaclass by setting special member:
class Parent(object):
__metaclass__ = Meta
...
See Python2 documentation
In Python 3, you set metaclass via keyword attribute in the parent list, so
class Parent(metaclass=Meta):
...
See Python3 documentation
The metaclass is a base class for the class instance. It has to be derived from type
and in it's __new__
it can modify the class being created (I believe the __init__
should be called too, but the examples override __new__
, so I'll go with it). The __new__
will be similar to what you have:
class Meta(type):
def __new__(mcs, name, bases, namespace, **kwargs):
new_cls = super(Meta, mcs).__new__(mcs, name, bases, namespace, **kwargs)
user_init = new_cls.__init__
def __init__(self, *args, **kwargs):
print("New __init__ called")
user_init(self, *args, **kwargs)
self.extra()
print("Replacing __init__")
setattr(new_cls, '__init__', __init__)
return new_cls
(using the Python 3 example, but the signature in Python 2 seems to be the same except there are no **kwargs
, but adding them shouldn't hurt; I didn't test it).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With