I’m having a great time here at PyCon. Lots of good information all over the place, which is awesome. Add to it the friendliness of everyone, and you really have one of the best conferences ever.
I attended a talk on Class Decorators (PEP 3129), this past Saturday and was very surprised. First, I don’t remember hearing anything about it. Secondly, it had never occurred to me to use decorators to initialize a class–even without the syntactic sugar that is offered by 2.6. Having done a couple of things with metaclasses, I have to say that class decorators are a much better answer.
Here are the key reasons–for me, at least–that makes class decorators The Way To Go:
- The decorator style is easier to implement.
- The decorator style is more explicit.
- Less worries about collisions in attribute names.
Right from the get-go, you can see that there are a few things you need to know about. There are 4 parameters to the
__new__ method, and I always get them wrong the first time. On top of that, you have to remember to use the
type.__new__ invocation return the new type. Then, you have to actually use it in the class:
Now, let’s say that I derive another class from Foo:
What’s missing here is that there could be some black-magic going on. What if the metaclass introduced new methods? How do I know where they came from looking at
Bar? Simple: I don’t. At least, not without digging into the actual definitions of
Let’s take a look at the identity version of the class decorator:
It’s extremely obvious what this does because of it’s simplicity and it’s directness. Now, let’s use it in Python 2.6 or greater:
If you’re using less that Python 2.6, do:
The decorator version is much simpler than the metaclass version. Additionally, you can see what’s being applied to the class because it’s explicitly marked. On top of that, in order to communicate parameters to the metaclass, you resort to doing things like:
If you get several metaclasses into the mix, you could end up with a naming collision and some unexpected behavior. With the decorator version, it would look like:
You don’t risk having a name collision here:
paramname is only seen by the decorator, not the actual class. Additionally, you can stack decorators:
As always, there is a trade off. The trade-off here is that class decorators don’t inherit. So, in the above example, if I had a subclass called
PdfIndexer, it would not get automatically registered nor would it be scheduled to run daily. Frankly, that’s a trade-off I’m happy to make.
In summary, if you’ve ever thought about using a metaclass, scrap the idea and use a class decorator instead. It’s definitely easier to understand, and easier to implement. Now I have a good reason to choose 2.6 as my default Python installation. :-)