[Python-ideas] A way out of Meta-hell (was: A (meta)class algebra)

Nick Coghlan ncoghlan at gmail.com
Thu Feb 19 12:10:05 CET 2015


On 18 Feb 2015 18:51, "Martin Teichmann" <lkb.teichmann at gmail.com> wrote:
>
> > Zope already implements __classinit__ via a metaclass, so I'm not clear
on
> > how this addition would help with a backport of the __init_class__
spelling
> > to Python 2.
>
> Well, there is just a small issue in the zope implementation. They don't
> support super(). So you cannot write:
>
>     from ExtensionClass import Base
>     class Spam(Base):
>         def __class_init__(self):
>             super().__class_init__(self)  # this line raises RuntimeError
>             # do something here
>
> The precise error is: RuntimeError: super(): empty __class__ cell
>
> My pure python implementation with __init_subclass__ support
> super() without problems.
>
> The problem is that at the point they call __class_init__ (at the end
> of ExtensionClass.__new__) the __class__ in the methods is not
> initialized yet. Interestingly, it also doesn't help to move that call
> into __init__, which is still a mystery to me, I was under the
> assumtion that at the point of __init__ the class should be fully
> initialized. Interestingly, type manages to set the __class__ of the
> methods AFTER __init__ has finished. How it manages to do so
> I don't know, but probably that's special-cased in C.

Yes, populating __class__ happens inside the interpreter only after the
class is fully constructed, so even though the *class* is fully initialised
at the end of __init__, a reference hasn't been inserted into the cell yet.
(The __class__ cell doesn't actually live on the class object - it's
created implicitly by the interpreter and then referenced from the
individual methods as a closure variable for each method that looks up
"__class__" or "super")

Python 2 doesn't provide the implicitly populated __class___ cell at all
though, so you have to refer to the class object by its name - zero
argument super is a Python 3 only feature.

> > I agree a clean idiom for detecting whether you're in the base class or
not
> > might be useful, but even without specific support in the PEP you'll at
> > least be able to do that either by inspecting the MRO, or else by
assuming
> > that the class name not being bound yet means you're still in the
process of
> > creating it.
>
> That sounds very complicated to me. Could you please give me an
> example how I am supposed to do that?

Second one is fairly straightforward - either do a check for the class name
in the module globals() or catching the resulting NameError.
Checking the MRO would be a bit more fragile, and likely not worth fiddling
with given the ability to check for the name binding of the base class
directly.

You also have the option of just setting an initialisation flag on the
class object itself (since the initial execution in the base class will
always be the first execution).

Cheers,
Nick.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-ideas/attachments/20150219/39e4917a/attachment.html>


More information about the Python-ideas mailing list