[Python-ideas] An even simpler customization of class creation

Martin Teichmann lkb.teichmann at gmail.com
Mon Mar 2 11:57:09 CET 2015


>> Fortunately, this is easily changeable: it is possible to move the
>> initialization of __class__ into type.__new__. As the class is
>> (typically) created there, that is about as early as possible.
>
> Unfortunately, it's too early - we can't control whether or not subclasses
> actually return the result of type.__new__ from their own __new__
> implementation, so that object could have been replaced by something else by
> the time __init__ gets called.

Well, this is actually just a question of definition and documentation.
Sure, a metaclasses __new__ may return whatever it pleases, but this
is not in contradiction of setting __class__ of the methods in type.__new__.

There are two possible scenarios:

1. metaclass.__new__ does not call type.__new__. Once we document that
it is type.__new__'s job to set __class__, nobody can complain if __class__
is not set if type.__new__ is not called, as this would be documented behavior.
In my changes I actually still left in the old code, so __build_class__ would
still try to set __class__ even if type.__new__ did not get called.

2. somehow type.__new__ does get called (most likely by metaclass.__new__).
It will do its job and set the __class__ of the methods of the class being
created. Whatever metaclass.__new__ returns then doesn't matter much,
because what sense would it make to set __class__ of that object it creates?

To give an example:
Imagine a soliton-generating metaclass:

    class Soliton(type):
       def __new__(cls, name, bases, ns):
           self = super().__new__(name, bases, ns)
           return self()

And generate such a soliton:

    class A(metaclass=Soliton):
        def f(self):
            print(__class__)

As of now, writing "A.f()" interestingly prints "<__main__.A object>", so
__class__ is indeed set to what Soliton.__new__ returns, the object,
not the class.

This is currently correct behavior, but I think it actually is not what one
expects, nor what one desires. (Does anyone out there make use of
such a construct? Please speak up!) super() certainly won't work.
So I think it would actually be a change for the better to let
type.__new__ set the __class__ of the generated class.

I know that it technically breaks backward compatibility. But I ran
all the tests and none failed, so apparently until now nobody got
weird ideas like me... I even tried to remove the old code from
__build_class__ and still all tests run. (just a note, if anyone else
here is trying to do so, I tampered with the compiler, so you better
delete your .pyc files before running the tests)

Greetings

Martin


More information about the Python-ideas mailing list