[Python-Dev] Possible rough edges in Python 3 metaclasses (was Re: Language reference updated for metaclasses)

Nick Coghlan ncoghlan at gmail.com
Tue Jun 5 01:18:07 CEST 2012


On Tue, Jun 5, 2012 at 8:58 AM, PJ Eby <pje at telecommunity.com> wrote:
> On Mon, Jun 4, 2012 at 6:15 PM, Nick Coghlan <ncoghlan at gmail.com> wrote:
>>
>> It's actually the pre-decoration class, since the cell is initialised
>> before the class is passed to the first decorator. I agree it's a little
>> weird, but I did try to describe it accurately in the new docs.
>
> I see that now; it might be helpful to explicitly call that out.
>
> This is adding to my list of Python 3 metaclass gripes, though.  In Python
> 2, I have in-the-body-of-a-class decorators implemented using metaclasses,
> that will no longer work because of PEP 3115...

I'm not quite following this one - do you mean they won't support
__prepare__, won't play nicely with other metaclasses that implement
__prepare__, or something else?

>  and if I switch to using
> class decorators instead, then they won't work because of PEP 3135.  :-(

Yeah, 3135 has had some "interesting" consequences :P (e.g. class body
level __class__ definitions are still broken at the moment if you also
reference super: http://bugs.python.org/issue12370)

> Meanwhile, mixing metaclasses is more difficult than ever, due to
> __prepare__, and none of these flaws can be worked around officially,
> because __build_class__ is an "implementation detail".  I *really* want to
> like Python 3, but am still hoping against hope for the restoration of hooks
> that __metaclass__ allowed, or some alternative mechanism that would serve
> the same use cases.
>
> Specifically, my main use case is method-level decorators and attribute
> descriptors that need to interact with a user-defined class, *without*
> requiring that user-defined class to either 1) redundantly decorate the
> class or 2) inherit from some specific base or inject a specific metaclass.
> I only use __metaclass__ in 2.x for this because it's the only way for code
> executed in a class body to gain access to the class at creation time.
>
> The reason for wanting this to be transparent is that 1) if you forget the
> redundant class-decorator, mixin, or metaclass, stuff will silently not
> work,

Why would it silently not work? What's preventing you from having
decorators that create wrapped functions that fail noisily when
called, then providing a class decorator that unwraps those functions,
fixes them up with the class references they need and stores the
unwrapped and updated versions back on the class.

You call it redundant, I call it explicit.

> and 2) mixing bases or metaclasses has much higher coupling to the
> library providing the decorators or descriptors, and greatly increases the
> likelihood of mixing metaclasses.

So don't do that, then. Be explicit.

> And at the moment, the only workaround I can come up with that *doesn't*
> involve replacing __build_class__ is abusing the system trace hook; ISTM
> that replacing __build_class__ is the better of those two options.

Stop trying to be implicit. Implicit magic sucks, don't add more (PEP
3135 is bad enough).

> At this point, with the additions of types.new_class(), ISTM that every
> Python implementation will have to *have* a __build_class__ function or its
> equivalent; all that remains is the question of whether they allow
> *replacing* it.

types.new_class() is actually a pure Python reimplementation of the
PEP 3115 algorithm. Why would it imply the need for a __build_class__
function?

Cheers,
Nick.

-- 
Nick Coghlan   |   ncoghlan at gmail.com   |   Brisbane, Australia


More information about the Python-Dev mailing list