After modifying a class as it's being created ( covered in part 1 ), the next thing you can do with a metaclass is get a chance to do things when instances of the class are created. You do this by defining
__call__
on your metaclass:
class MiniMeta(type):
def __call__(cls, *args, **kwargs):
return super(MiniMeta, cls).\
__call__(*args, **kwargs)
class Example(object):
__metaclass__ = MiniMeta
There are a number of things that you can do with this. One of them (which I first saw in another metaclass tutorial) is handling deferred initialization and setup of something related to the class. Rather than doing this in your metaclass
__new__
or
__init__
, you defer it until the first time an instance of the class is created; this saves you effort in situations where many classes are defined but only a few classes will ever be used to create instances.
Using a metaclass
__call__
to customize instance creation runs into the obvious question of why you don't just do the same work in the class's own
__init__
method (or in extreme cases, its
__new__
method). Probably the right answer is if you have a chunk of common behavior across a bunch of classes and the classes can't easily be put into an inheritance relationship where this functionality can be pulled into a common ancestor or mixin class.
(This use of metaclasses is considered sufficiently interested to get mentioned in passing in the official documentation for
__metaclass__
.)
PS:
__call__
is actually a specific example of a general metaclass power. I'll get to the general power later because it requires more explanation.
Sidebar: a technicality
Strictly speaking using
__call__
does not intercept all instance creation, since a sufficiently creative person can still obtain new instances of
Example
by calling
object.__new__()
directly. If you're doing something where you have to worry about this, Python is probably the wrong language to write your code in.