Using metaclasses to play with decorators.

Colin J. Williams cjw at sympatico.ca
Sun Jun 20 20:48:23 CEST 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