Using metaclasses to play with decorators.
Colin J. Williams
cjw at sympatico.ca
Sun Jun 20 14:48:23 EDT 2004
Robert Brewer wrote:
> j_mckitrick wrote:
>
>>You guys are WAY over my head, and I'm supposed to be a C.S.
>>junior! :-\
>>
>>Could someone give me an idea of what metaclasses and
>>decorators _are_?
>
>
> Sure thing.
>
>
>>I think metaclasses are classes with their base methods
>>overridden, correct?
>>
>>And decorators are a form of delegation, right?
>
>
> Oh, and you were doing so well until you guessed... ;)
>
>
>>If so, where am I wrong? And how do these techniques make
>>for better code/coding?
>
>
> Metaclasses are mind-demolition tools:
>
> http://www.python.org/2.2/descrintro.html#metaclasses
>
> As a CS student, you're probably familiar with the concept of a
> 'factory': a block of code which forms objects of a given class. In
> Python, classes are also objects. A metaclass can be thought of as a
> 'class factory': a factory which produces classes (as opposed to
> instances of classes). To say it another way, a class can loosely be
> considered a template for objects; a metaclass is a template for
> classes.
>
> Metaclasses allow you to customize the creation of classes. A common use
> is when you have a base class, let'a call it A, and you want to provide
> a behavior for each subclass "class B(A)", C, D... For example, you
> might want to 'register' each subclass in a module-level list. You can
> do this without metaclasses:
>
> class A(object):
> pass
>
> class B(A):
> custom_data = {}
>
> class C(A):
> funky_stuff = []
>
> subclasses_of_A = [B, C]
>
> ....but that can get tedious, especially if you aren't writing the
> subclasses (perhaps you're writing a framework). Whenever anyone writes
> a subclass (perhaps in a different module), they have to remember to
> append their new subclass to subclasses_of_A.
>
> Metaclasses solve this by customizing class-creation code. In our
> registration example, we might write:
>
> subclasses_of_A = []
>
> class RegisterA(type):
> def __init__(cls, name, bases, dct):
> subclasses_of_A.append(cls)
>
> class A(object):
> __metaclass__ = RegisterA
>
> class B(A):
> custom_data = {}
>
> class C(A):
> funky_stuff = []
>
> Testing this (we'll save our module as 'metatest.py'), we obtain
> (PythonWin 2.3.2):
>
>
>>>>import metatest
>>>>metatest.subclasses_of_A
>
> [<class 'metatest.A'>, <class 'metatest.B'>, <class 'metatest.C'>]
>
> When we declare class A, we are creating a new object 'A' which happens
> to be a class. By giving it a __metaclass__ attribute, we can customize
> the creation of class A. RegisterA doesn't override type.__new__, so
> type.__new__ forms the new class as usual. RegisterA does override
> __init__, so RegisterA.__init__ gets called with our new (empty) class A
> as the first argument, at which point we append metatest.A to our list.
> I'll leave you to figure out how to exclude A but keep all the
> subclasses ;) Exercise 2 would be to make this mechanism generic (that
> is, keep subclasses_of_A separate from subclasses_of_Thing).
>
> ================================
>
> Decorators are a very recent discussion; you might want to browse recent
> threads on python-dev for a lot more information. You should certainly
> read PEP 318 (http://www.python.org/peps/pep-0318.html). Basically, a
> decorator is a way to transform a function. Again, this can usually be
> done without metaclasses. The most-frequently-discussed examples are
> staticmethods and classmethods:
>
> class Thing(object):
> def newThing(cls, attr):
> t = cls()
> t.attr = attr
> return t
> newThing = classmethod(newThing)
>
> Decorators will hopefully provide a clearer syntax for saying the same
> thing (although the exact syntax is still up for debate):
>
> class Thing(object):
> def newThing(cls, attr) [classmethod]:
> t = cls()
> t.attr = attr
> return t
>
> This moves the transformation ('classmethod') closer to the function
> definition, rather than placing it at the end of the function. In
> addition, you don't have to write the name 'newThing' three times. Also,
> multiple transforms could be defined at once.
>
> Does that help?
>
>
> Waiting expectantly for a heapin' helpin' of picked nits,
>
> Robert Brewer
> MIS
> Amor Ministries
> fumanchu at amor.org
>
I don't wish to pick nits, but to suggest that GVD defined metaclasses
as classes whose instances are classes. This seems straighforward.
I have yet to wrap my mind around decorators.
Colin W
More information about the Python-list
mailing list