[Python-Dev] What is the design purpose of metaclasses vs code generating decorators? (was Re: PEP 557: Data Classes)

Nick Coghlan ncoghlan at gmail.com
Sat Oct 14 11:38:15 EDT 2017


On 15 October 2017 at 01:00, Martin Teichmann <lkb.teichmann at gmail.com>
wrote:

> While I am not worried about the poor computers having to do a lot of
> work creating a throwaway class, I do see the problem with the new
> super. What I would like to see is something like the @wraps decorator
> for classes, such that you could write something like:
>
>     def class_decorator(cls):
>         @wraps_class
>         class MyNewCoolClass:
>               """my cool functionality here"""
>          return MyNewCoolClass
>
> wraps_class would then copy over everything such that the new class gets
> it.
>
> Unfortunately, this won't work, because of the new super. The new
> super is about the only thing that cannot be dynamically changed in
> Python. While it is no problem to make a function a method of a random
> class (just use __get__), it is not possible to move a function from
> one class to another, because you cannot change its binding to
> __class__, which is used by super(). And even if we could, the method
> whose __class__ we want to change might hide in a wrapper.
>

Up until 3.6, we made it so that the class cell for zero-arg super was an
almost entirely hidden implementation detail at class creation time. To
allow zero-arg super() class methods to work from __init_subclass__, we
changed that to include __classcell__ in the execution namespace passed to
the metaclass.

So it seems to me that to enable the class *replacement* use case, we'd
only need one new thing: access to that cell as an attribute on the class
itself. That way, when creating the new class you could set
"ns['__classcell__'] = old_cls.__classcell__" before calling the new
metaclass, which would allow the new class to take over zero-arg super()
resolution for any methods defined lexically inside the original.

For the class *duplication* use case (where you want to leave the original
class intact), the main thing this would let you do is to reliably detect
that there is at least one method in the class body using the zero-arg
super() form (when cls.__classcell__ is non-None), and either issue a
warning or fail outright (since methods that rely on cooperative multiple
inheritance need a specific defining class or else the runtime parent
resolution gets inconsistent).

Cheers,
Nick.

-- 
Nick Coghlan   |   ncoghlan at gmail.com   |   Brisbane, Australia
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-dev/attachments/20171015/be2e5372/attachment-0001.html>


More information about the Python-Dev mailing list