What can be done with metaclasses that can't be in any other way?
Alex Martelli told that there are tasks that can't be achieved without metaclasses here Python metaclasses vs class decorators I'd like to know which are?
What can be done with metaclasses that can't be in any other way?
Alex Martelli told that there are tasks that can't be achieved without metaclasses here Python metaclasses vs class decorators I'd like to know which are?
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):If you have this as a tool, and you're using a class which must know its
name
before it cando_something()
:It can make the difference in the rest of your code between this:
and this:
Thus reducing duplication (and the chances that the variable name and the assigned name might get out-of-sync).
Take a look at Django sources - for example metaclasses are used there to generate models.
http://code.djangoproject.com/wiki/DynamicModels
Probably there is nothing that can be done exclusively with metaclasses, but to some people (mine included) it's a interesting tool you can use. Just be careful not to abuse, as it can be tricky.
For example, I've used metaprogramming in a recent project. It was a OpenOffice calc sheet, which, using some pyUNO macros, generates some files with information. There was one sheet that presents to the user the information to fill, and the others can be used to describe the kind of elements and their properties. The user can then select the number of elements and the type of each, and generate the files. The macro will create a class via metaprogramming following the configuration on each sheet. Then, the user can instanciate each class and generate objects.
It could be done without metaprogramming, but to me seemed natural to use the metaprogramming capabilities to do it.
If you are looking for examples of using the metaclass mechanism, you can read the source code of django.forms.
The declarative style of form definition is implemented through metaclass.
Add extra flexibility to your programming:
But according to this Metaclass programming in Python you might not need them ( yet )
Metaclasses are indispensable if you want to have class objects (as opposed to instances of class objects) equipped with "special customized behavior", since an object's behavior depends on special methods on the type of the object, and a class object's type is, exactly a synonym for, the metaclass.
For example, if you want a class object X such that "print X" emits "Time is now 8:46am" (at 8:46 am, or, more generally, the current time) this must mean that
type(x)
(AKA X's metaclass) has a special custom__str__
method -- and similarly (with the various applicable special-methods) if you want to give meaning to expressions such asX + Y
where X and Y are both class objects, orX[23]
(where X, again, is a class object), and so forth.Most other customization tasks are now (in Python 2.6 or better) easier to implement with a class decorator, which can alter a class object right after the end of the
class
statement. There are a few more cases where this is not feasible because the alterations must be made very early on if they are to have any effect (e.g., setting or altering__slots__
).In Python 3, metaclasses gain one extra little bit of usefulness: a metaclass can now optionally specify the mapping object to be populated during the execution of the
class
statement's body (by default, it's a normaldict
). This allows the order of name bindings in the class body to be preserved and used (while the normaldict
loses order), which is sometimes nice when the class must have "fields" in a certain specific order (e.g. to map 1:1 onto a Cstruct
, a row in a CSV file or DB table, and the like) -- in Python 2.* this had to be redundantly specified (typically with an extra class attribute that's a sequence and thus does preserve order), and this feature of Python 3 metaclasses allows the redundancy to be removed.