An operational explanation of Python metaclasses (part 2)

September 17, 2011

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.

Written on 17 September 2011.
« Setting the character encoding for HTML form input
An operational explanation of Python metaclasses (part 3) »

Page tools: View Source, Add Comment.
Login: Password:
Atom Syndication: Recent Comments.

Last modified: Sat Sep 17 00:49:55 2011
This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.