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

Martin Teichmann lkb.teichmann at gmail.com
Sat Oct 14 11:00:44 EDT 2017


I do worry that things like your autoslots decorator example might be problematic because they create a new class, throwing away a lot of work that was already done. But perhaps the right way to address this would be to move the decision about the instance layout to a later phase? (Not sure if that makes sense though.)

--Guido Just FYI, recreating the class with slots runs into problems with regards to PEP 3135 (New Super). In attrs we resort to black magic to update the class cell in existing methods. Being able to add slotness later would be good, but not that useful for us since we have to support down to 2.7.

You're both bringing up an important point here: while in function decorators it is normal to return a completely new function (albeit one that wraps the original), this is close to impossible for classes. You cannot just wrap a class in another one. You may inherit from it, but that's already often not what one wants.

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.

The current behavior of class is weird, it is set to the class that type.new creates. So even if another metaclasses new or a decorator returns another class, the method's class would still point to the original class, which might even not exist anymore.

One might argue that this is due to the fact that it is not well-defined what class should be set to. But this is not true, it is crystal clear: class should be set to the class from whose dict the method was drawn. I thought about a new three-parameter get(self, instance, owner, supplier), which would then set class to the supplier. This is a beautiful concept, that is unfortunately not so simple when it comes to methods hidden in wrappers.

Greetings

Martin



More information about the Python-Dev mailing list