I use metaclasses with some frequency, and they're an extremely powerful tool to have in the toolbox. Sometimes your solution to a problem can be more elegant, less code, with them than without.
The thing I find myself using metaclasses for most often, is post-processing the class attributes during class creation. For example, setting a name
attribute on objects where appropriate (like how the Django ORM might work):
class AutonamingType(type):
def __init__(cls, name, bases, attrs):
for k,v in attrs.iteritems():
if getattr(v, '__autoname__', False):
v.name = k
class Autonamer(object):
__metaclass__ = AutonamingType
If you have this as a tool, and you're using a class which must know its name
before it can do_something()
:
class Foo(object):
__autoname__ = True
def __init__(self, name=None):
self.name = name
def do_something(self):
if self.name is None:
raise ValueError('name is None')
# now, do something
It can make the difference in the rest of your code between this:
class Bar(object):
myfoo1 = Foo('myfoo1')
myfoo2 = Foo('myfoo2')
myfoo3 = Foo('myfoo3')
and this:
class Baaz(Autonamer):
myfoo1 = Foo()
myfoo2 = Foo()
myfoo3 = Foo()
Thus reducing duplication (and the chances that the variable name and the assigned name might get out-of-sync).