[Python-3000] PEP for Metaclasses in Python 3000
Jack Diederich
jackdied at jackdied.com
Wed Mar 14 17:57:40 CET 2007
On Mon, Mar 12, 2007 at 05:30:48PM -0700, Guido van Rossum wrote:
> Executive summary: I'm defending the PEP and the metaclass syntax it
> proposes, and in fact I want the "clas arguments" to have the same
> syntax as a call, including *args and **kwds. I'm only suggesting to
> find a new name instead of __metacreate__.
>
> While I'm responding to the first message in the thread, I've actually
> read the entire thread, and I'm responding in tit-for-tat mode to much
> of it. (Yes, you'll find that there are actually a few messages in the
> thread so far to which I *didn't* respond, and even some by Greg
> Ewing. :-)
I've snipped all the bits I understand and/or agree with.
First, is this an accurate summary of the current proposal?
class A(metaclass=meta): pass
mydict = meta.__prepare__(name, bases, **kwds)
cls = meta.__new__(name, bases, mydict, **kwds)
meta.__init__(cls, name, bases, mydict, **kwds)
A = cls
> On 3/9/07, Jack Diederich <jackdied at jackdied.com> wrote:
> > I am a very big fan of ordered dicts in classes.
>
> Would you mind showing us some of your use cases / examples?
This has only come up for me when using classes as namespaces. In
a rule based application it was important to know the order of precedence.
There are ways to work around it but they are a bit hackey.
next_id = iter(xrange(1000)).next
class Series700:
housing = Plastics(order=next_id())
pins = Integer(0, 50, order=next_id())
(in reality the next_id() was called in the Plastics and Integer __init__s)
I did a similar thing when making PLY class based instead of module
based so I could have many grammars in a module. The other approach
is what PLY does - When you look at the top of a PLY module you will
see a list of strings that are the names of rules. The order of the
list is the order in which the rules are applied.
Also, the only non-cosmetic reasons listed in the PEP are all
for ordered dicts!
> On 3/10/07, Josiah Carlson <jcarlson at uci.edu> wrote:
> > Generally, about the only need I forsee for arbitrary keyword arguments
> > in the class 'foo(...)' signature is to pass arguments to the 'metadict'
> > factory (method, function, etc.). Otherwise it seems more like a syntax
> > looking for a purpose than a purpose looking for a syntax.
>
> Or to the metaclass later on. I see keyword args as a way to pass
> parameters to a metaclass that would otherwise have to be assigned to
> class variables, in a namespace that's much more crowded. Imagine
> being able to write this:
>
> class C(implements=(I1, I2)):
> ...
I don't understand the keyword args other than 'metaclass.'
If class D inherits from class C does it also get passed the 'Implements'
keyword? If it does the same effect could be acheived by making a metaclass
maker function and just using the metaclass keyword.
class C(metaclass=Implements(I1, I2)):
...
If D doesn't get the 'Implements' keyword then the one-off behavior
would be easier to put in a class decorator than a metaclass.
Keywords also strike me as hard to stack. If a class has two keywords
defining unrelated behaviors the metaclass would have to be a library-like
thing that understood both of them. Mixing metaclasses from two seperate
metaclass libraries would be hard - no harder than it currently is but
keywords will invite more use.
> On 3/10/07, Greg Ewing <greg.ewing at canterbury.ac.nz> wrote:
> > I still think that extra arguments are unnecessary in
> > any case, because anything you could do by passing args
> > to the dict creation function could be done by using a
> > function instead of a class for the "metaclass".
> >
> > Does anyone have a counter-example?
>
> Not that you couldn't write it your way, but I find this rather cool looking:
>
> class C(implements=(I1, I2)): ...
I like the more explicit
class C(metaclass=Implements(I1, I2)):
...
> On 3/10/07, Greg Ewing <greg.ewing at canterbury.ac.nz> wrote:
> > Note that you can already pass information to the
> > metaclass itself using special attributes in the class
> > namespace. This would only be need if you absolutely
> > had to pass information when creating the *dict*.
> > Things like your 'sealed' option don't seem to fall
> > into that category.
>
> I don't know about sealed, but using class attributes topassing
> parameter (other than the namespace itself) to the metaclass seems a
> pretty lousy mechanism, and keyword arguments in the classdef are a
> much cleaner solution for this need. For example, this solves the
> problem that those attributes remain in the class dict but aren't
> necessarily candidates for inheritance (example: __slots__, whose
> inheritance story is, um, complicated; in general C.__slots__ does not
> necessarily tell you all the slots that the class has).
Agreed, I currently use metaclasses that pull behavior flags from the
class body and it is less than pretty. In my experience when you have
those behavior flags in the class they change for every subclass too.
If they didn't they would be defined in the original metaclass. I think
of metaclasses as 'apply always' and class decorators as 'apply once.'
Everyone seems to have some loose ideas of what they would use the
keywords for but I'm hung up on why this
class C(metaclass=meta_library,
sealed=True,
implements=(I1, I2)):
...
is preferable to this
@seal
@implements(I1, I2)
class C():
...
or even this
class C(metaclass=meta_library(sealed=True, implements=(I1, I2))):
...
-Jack
More information about the Python-3000
mailing list