As discussed in the metaclasses definition, whenever an object is created for a class, the
__call__ method of a metaclass is called which in turn calls the
__new__ and then
__init__ method of the class for which the object is created.
class Foo: pass f = Foo()
f is created, the metaclass of
Foo which is
type calls the
__new__ method in
Foo. But since
Foo doesn’t implement the method
__new__ , it tries to invoke the method from the
Foo’s ancestor which in this case would be
With that, if you want to override the object instantiation for any object, just implement
__new__ in the object as below.
class Foobar: def __init__(self): self.var = "Hello World!" def __new__(cls): print("Creating instance") return super().__new__(cls) x = Foobar() // Creating instance print(x.var) // Hello World!
In the same way, since the
class is an object of
type metaclass, the instantiation of the class can be customized by overriding
__new__ in the metaclass.
def new(cls): x = type.__new__(cls) x.val = "Hello World!" return x // Here x is a class object type.__new__ = new // TypeError: can't set attributes of built-in/extension type 'type' class Foo: pass
Though the above code makes sense, python won’t allow setting attributes to
type class directly and even if it does, it will end up an infinite loop. So to overcome this, we need to create a custom metaclass to achieve what we want. Custom metaclasses are user-defined metaclasses which are derived from
type metaclass. So let’s define a custom metaclass first.
class CustomMeta(type): def __new__(cls, name, bases, dict): x = super().__new__(cls, name, bases, dict) x.val = "Hello World!" return x
The above metaclass just overrides
__new__ method and creates the intended class object whenever class code is executed. Now let’s see how to use this custom metaclass.
class Foo(metaclass=CustomMeta): pass f = Foo() print(f.val) // Hello World! print(Foo.val) // Hello World!
Here we have defined a class and specified it’s metaclass using the
metaclass keyword. Now all the classes with this custom metaclass will have attribute
val assigned to it automatically. We can use it as a class factory.