22

Per the 3.6.0 docs:

CPython implementation detail: In CPython 3.6 and later, the __class__ cell is passed to the metaclass as a __classcell__ entry in the class namespace. If present, this must be propagated up to the type.__new__ call in order for the class to be initialized correctly. Failing to do so will result in a DeprecationWarning in Python 3.6, and a RuntimeWarning in the future.

Can someone provide an example of doing this correctly?

An example where it's actually needed?

1

1 Answer 1

19
+50

The warning is raised if you use super that relies on __class__ being available or reference __class__ inside the class body.

What the text essentially says is that, this is needed if you define a custom meta-class and tamper with the namespace you get before passing it up to type.__new__. You'll need to be careful and always make sure you pass __classcell__ to type.__new__ in your metaclass.__new__.

That is, if you create a new fancy namespace to pass up, always check if __classcell__ is defined in the original namespace created and add it:

class MyMeta(type):
    def __new__(cls, name, bases, namespace):
        my_fancy_new_namespace = {....}  
        if '__classcell__' in namespace:
             my_fancy_new_namespace['__classcell__'] = namespace['__classcell__']
        return super().__new__(cls, name, bases, my_fancy_new_namespace)

The file you linked in the comment is actually the first of many attempted patches, issue23722_classcell_reference_validation_v2.diff is the final patch that made it in, from Issue 23722.

An example of doing this correctly can be seen in a pull request made to Django that uses this to fix an issue that was introduced in Python 3.6:

new_attrs = {'__module__': module}
classcell = attrs.pop('__classcell__', None)
if classcell is not None:
    new_attrs['__classcell__'] = classcell
new_class = super_new(cls, name, bases, new_attrs)

The __classcell__ is simply added to the new namespace before being passed to type.__new__.

Sign up to request clarification or add additional context in comments.

3 Comments

It took me a while to find out it is created if any method inside the class uses the super() form. This comes likely because before it was impossible to call any classmethod that would make use of super() inside the metaclass methods itself. More likely, the new __init_subclass__ mechansm in Python 3.6 needs it.
@jsbueno yup, __init_subclass__ with a custom metaclass, though. If you use type you're fine.
@JimFasarakis-Hilliard could you provide a reference or a simple example to illustrate custom namespace?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.