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

Petr Viktorin encukou at gmail.com
Sat Feb 14 12:47:17 CET 2015


On Sat, Feb 14, 2015 at 12:18 PM, Martin Teichmann
<lkb.teichmann at gmail.com> wrote:
> Hi Petr, Hi all,
>
>> Just putting it in the standard library doesn't make sense, since it
>> would still only be available there from Python 3.5 on (or whenever it
>> gets in).
>> It really makes more sense to put this into the *real* standard
>> metaclass (i.e. `type`).
>> The Python implementation can be on PyPI for projects needing the
>> backwards compatibility.
>
> That was what I was thinking about. Put the python implementation
> on PyPI, so everyone can use it, and finally put the thing in the
> standard library.
>
> I actually prefer the standard library over adding it to type, it's
> much less a hazzle. Given that there are use cases for metaclasses
> not covered by PEP 422, I guess they won't ever be dropped,
> so having two complicated things in C are not such a great idea in
> my opinion if we can easily write one of them in Python.

No. For anyone to take this seriously, it needs to be what `type` itself does.
The PyPI library then can just do "WithInit = object" on new Python versions.
But that's beside the point right now; if you can write this then it
can be integrated either way.

Also, I'm now not sure how easily you can write this in Python, since
you're already starting to take shortcuts below.

>> Not really, but you can rewrite the metaclass as a C extension (maybe
>> after the Python variant is ironed out).
>
> Well said, and yes, it needs ironing out. I just realized it doesn't work
> since I'm calling __init_class__ before its __class__ is set. But this
> is a solvable problem: Let's rewrite PEP 422 so that the initialization
> is done on subclasses, not the class itself. This is actually a very
> important usecase anyways, and if you need your method to be
> called on yourself, just call it after the class definition! One line of
> code should not be such a big deal.

-1, that would be quite surprising behavior.
If doing the right thing is really not possible in Python, then I
guess it does need to go to the C level.

> I also simplified the code, requiring now that decorates __init_subclass__
> with @classmethod.

You're writing library code. A bit more complexity here i worth it.
See again the Rejected Design Options in the PEP.

> class Meta(type):
>     @classmethod
>     def __prepare__(cls, name, bases, namespace=None, **kwargs):
>         if namespace is not None:
>             cls.__namespace__ = namespace
>         if hasattr(cls, '__namespace__'):
>             return cls.__namespace__()
>         else:
>             return super().__prepare__(name, bases, **kwargs)
>
>     def __new__(cls, name, bases, dict, **kwargs):
>         return super(Meta, cls).__new__(cls, name, bases, dict)
>
>     def __init__(self, name, bases, dict, namespace=None, **kwargs):
>         super(self, self).__init_subclass__(**kwargs)
>
>
> class Base(object):
>     @classmethod
>     def __init_subclass__(cls, **kwargs):
>         pass
>
> SubclassInit = Meta("SubclassInit", (Base,), {})

I think it's time you put this in a repository; e-mailing successive
versions is inefficient.
Also, run the tests on it -- that might uncover more problems.


More information about the Python-ideas mailing list