As he says himself at the end, these aren't used very often because they aren't very useful.
The example at the end is perfectly well written using the class statement and using register as a class decorator, while being more familiar and readable.
It gets tiring to hear people say "oh advanced Python? Like metaclasses, I'll learn that".
Learn useful things instead, like writing readable, testable code.
Whenever I teach a course in advanced Python, the people asking for the training specifically request/demand that I talk about metaclasses. This is almost certainly because they (1) want an advanced class, and (2) metaclasses are advanced. So yeah, I cover them to some degree in my courses, but I give plenty of advance warning that we're looking at this because it's fascinating to see how some of the deeper recesses of Python classes work, not because this will truly be useful.
Sure enough, when I'm done with my explanation, the participants agree that metaclasses are really something that they're not planning to touch or use. And then I repeat my claim (which isn't original with me at all) that decorators are easier to understand and maintain, and should be used instead.
I totally agree that learning to write readable, testable code is a far better use of time. (I include that in my classes, too... but people rarely request that, I'm afraid...)
The example at the end is perfectly well written using the class statement
No, it can't, because the name of the class is dynamically determined at run time. The class statement can't take a variable for the name of the class. That's the point.
I think it was David Beazley who characterized metaclasses as "infecting" an inheritance tree. If `class A` has a metaclass, then all subclasses of `A` will inherit the metaclass as well. This behavior is not shared by class decorators, which only affect the decorated class.
So, I think this is a pretty reasonable place to use them -- getting magic behavior from class decorators / metaclasses is bad enough, but getting surprised when losing it upon subclassing is even worse!
It's trivial to enforce a constraint from a derived type to a base type. e.g.,
# base.py
class Base:
def spam(self): pass
# derived.py
class Derived(Base):
assert hasattr(Base, 'spam') # or abc, &c.
def ham(self):
return self.spam
But how can we enforce a constraint in the other direction? (e.g., abc.ABCMeta)
# base.py
from functools import wraps
class metaclass(type):
def __new__(m, n, b, d):
assert 'spam' in d # must implement, not just inherit
# can even enforce behaviour via wrapping
spam = d['spam']
@wraps(spam)
def wrap(*args, **kwargs):
print('wrap({}, {})'.format(args, kwargs))
return spam(*args, **kwargs)
d['spam'] = wrap
return type.__new__(m, n, b, d)
class Base(metaclass=metaclass):
def spam(self): pass
# derived.py
class Derived(Base):
def spam(self): pass
yeah, making things complicated just for the sake of making things complicated sucks. that said, model forms are one of the most useful parts of django, and they use metaclasses, although for all i know, ModelForm could have been implemented another way.
i only know about that part of the django implementation because i was trying to set up some kind of class inheritance and found that things were behaving strangely. so the conclusion in this case was that the use of metaclass allowed some cleverness in the implementation of ModelForm, but it made it difficult to layer more cleverness on top of ModelForm.
I think the reason type is used in the last example is to have the name of the class correspond with the table name. Otherwise a regular class would suffice like you say.
Did anyone pick up the OP's book, "Writing Idiomatic Python"? I'm tempted to buy, as someone new to Python. Looks like it may be useful for learning some Python best practices.
I'd like to buy the book, but is it really necessary to enter my email and password, twice each, then give my address, all to give you money through PayPal?
This is probably my all-time favorite StackOverflow post!