PEP 318 (was Re: [Python-Dev] Re: Guido's Magic Code was: inlinesort option)

Phillip J. Eby pje at telecommunity.com
Tue Nov 4 11:30:11 EST 2003


At 09:24 AM 11/4/03 +0100, Alex Martelli wrote:
>On Tuesday 04 November 2003 02:09 am, Phillip J. Eby wrote:
>    ...
> > I'm not all that enthused about the metaclass usage, mainly because there's
> > already an okay syntax (__metaclass__) for it.  I'd rather that class
>
>Hmmm -- why is:
>
>class Foo:
>     __metaclass__ = MetaFoo
>     ...
>
>"ok", compared to e.g.:
>
>class Foo is MetaFoo:
>     ...
>
>while, again for example,
>
>     def foo():
>         ...
>      foo = staticmethod(foo)
>
>is presumably deemed "not ok" compared to e.g.:
>
>     def foo() is staticmethod:
>         ...
>
>???

Isn't it obvious from the above?  Note the positioning of the '...' in all 
but the third example you've shown.  :)


> > decorators (if added) were decorators in the same way as function
> > decorators.  Why?  Because I think that correct, combinable class
> > decorators are probably easier for most people to write than correct,
> > combinable metaclasses, and they are more easily combined than metaclasses
> > are.
>
>Combinable metaclasses may not be trivial to write, but with multiple
>inheritance it will often be feasible (except, presumably, when implied
>layout or __new__ have conflicting requirements).

I guess my point is that it's harder to *learn* how to write a co-operative 
metaclass, than it is to simply *write* a co-operative decorator.  A 
metaclass must explicitly invoke its collaborators, but a decorator is just 
a simple function; the chaining is external.  Now, certainly you and I both 
know how to write our metaclasses co-operatively, but I believe both of us 
have also been told (repeatedly) that we're not typical Python programmers.  :)



>   Of course, not having use
>cases of either custom metaclasses or class decorators in production use, the
>iscussion does risk being a bit abstract.  Did you have any specific use case
>in mind?


PyProtocols has an API call that "wants" to be a class decorator, to 
declare interface information about the class, e.g:

class MyClass is protocols.instancesProvide(IFoo):
     ....

But, since there are no such things as class decorators, it actually uses a 
sys._getframe() hack to replace the metaclass and simulate 
decoratorness.  Steve Alexander originally proposed the idea as an 
implementation technique for interface declarations in Zope 3, and I worked 
up the actual implementation, that's now shared by PyProtocols and Zope 
3.  So the above is actually rendered now as:

class MyClass:

     protocols.advise(instancesProvide=[IFoo])

(Note that any explicit __metaclass__ declaration has to come *before* the 
advise() call.)  The principal limitation of this technique is that writing 
co-operative decorators of this sort is just as difficult as writing 
co-operative metaclasses.  So, PyProtocols and Zope 3 include a library 
function, 'addClassAdvisor(decorator_callable)' which adds a decorator 
function (in a PEP 218-style execution order) to those that will be called 
on the resulting class.

IOW, we created a decorator mechanism for classes that is almost identical 
to the PEP 218 mechanism for functions, to make it easy to call functions 
on a created class, using declarations that occur near the class 
statement.  This was specifically to make it easier to do simple 
decorator-like things, without writing metaclasses, and thus not 
interfering with user-supplied metaclasses.

Note, by the way, that since you can only have one explicit metaclass, and 
Python does not automatically generate new metaclasses, users must 
explicitly mix metaclasses in order to use them.  That's all well and good 
for gurus such as ourselves, but if you're creating a framework that wants 
to play nicely with other frameworks, and is for non-guru users, then 
metaclasses are right out unless they're the *only* way to achieve the 
desired effect.  For supplying framework metadata, decorators are an 
adequate mechanism that's simpler to implement, and are therefore 
preferable.  Since the 'addClassAdvisor()' mechanism has been available, 
I've used it for other framework metadata annotations, such as security 
restrictions, and to perform miscellaneous other "postprocessing" 
operations on classes.

Now, in the time since Steve Alexander first proposed the idea, I've 
actually grown to like the in-body declaration style for classes, and it's 
possible that PEP 218-style declaration for classes would be more 
unwieldy.  So I'm only +0 on having a class decorator syntax at all.  But I 
do think that if there *is* a class decorator syntax, its semantics should 
exactly match function decorator syntax, and am therefore -1 on it being 
metaclass syntax.  In my experience, non-guru usage of metaclasses is 
usually by inheriting the metaclass from a framework base class, and this 
is the "right way to do it" because the user shouldn't need to know about 
metaclasses unless they are mixing them.  (And if Python mixed them for 
you, there'd be no need for non-gurus to know about metaclasses at all.)




More information about the Python-Dev mailing list