Python magic methods (1) : __new__() and __init__()
In Python, magic methods are special methods where you can define to add “magic” to classes. They’re always surrounded by double underscores (called ‘dunder’). We will look into these magic methods in Object construction and initialization and see how they add advantages to python object oriented programming.
Object construction and initialization
- __new__(cls, […): the first method to get called in an object’s instantiation
- __init__(self, […): the method get called to create objects of class
From the definition above, we see that __new__() accepts cls as it’s first parameter, while __init__() accepts self. __init__() is called after __new__() when object is initialized.
Let’s take a look at example below.
class MyClass(object):
def __new__(cls):
print "MyClass.__new__ called"
return super(MyClass, cls).__new__(cls) # here super is type
def __init__(self):
print "MyClass.__init__ called"
if __name__ == '__main__':
c = MyClass()
Result:
MyClass.__new__ called
MyClass.__init__ called
As we can see, __new__() method took cls as the input to create self object, then when a new MyClass object is instantiated, __init__() is called thereafter.
Another thing to note: __new__() is called automatically when calling the class name, which is when we do MyClass(). On the other hand, __init__() is called every time an instance of the class is returned by __new__() passing the returned instance to __init__() as ‘self’.
As such, __new__() will return the instance of cls, and then, this new instance will be picked up by __init__(). If we ommit calling super for __new__() and not return anything, then __init__() won’t be executed.
When to use __new__()?
If you want to control the actual creation process, use the __new__() method. If you intend to alter something like the base classes or the attributes, you’ll have to do it in __new__().
Below example is to help to create a customized list with a method , “add”. By default, python list doesn’t have add method, but in this example we can create this customized list by adding add to the attr of the metaclass in __new__() method.
class ListMetaclass(type):
def __new__(cls, name, bases, attrs):
attrs['add'] = lambda self, value: self.append(value)
return type.__new__(cls, name, bases, attrs)
class MyList(list):
__metaclass__ = ListMetaclass # use ListMetaclass to customize class
if __name__ == '__main__':
#c = MyClass()
l = MyList()
l.add(1)
print (l)
Result:
[1]
The result shows this MyList() instance has a method add which adds elements to the list.