Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Provide __classcell__ example for Python 3.6 metaclass

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?

like image 328
Dima Tisnek Avatar asked Dec 27 '16 10:12

Dima Tisnek


People also ask

What metaclass does Python use to create the person class?

When Python executes the code, it uses the type metaclass to create the Person class. The reason is that the Person class uses the type metaclass by default. The explicit Person class definition looks like this:

What is the use of a class in Python?

Classes provide a means of bundling data and functionality together. Creating a new class creates a new type of object, allowing new instances of that type to be made. Each class instance can have attributes attached to it for maintaining its state.

Why can’t I inherit from two metaclasses in Python?

Here you will get the below error message while trying to inherit from two different metaclasses. This is because Python can only have one metaclass for a class. Here, class C can’t inherit from two metaclasses, which results in ambiguity. In most cases, we don’t need to go for a metaclass, normal code will fit with the class and object.

What is the primary metaclass of a class?

Summary. Normal classes that are designed using class keyword have type as their metaclasses, and type is the primary metaclass. Metaclasses are a powerful tool in Python that can overcome many limitations. But most of the developers have a misconception that metaclasses are difficult to grasp.


1 Answers

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__.

like image 108
Dimitris Fasarakis Hilliard Avatar answered Sep 19 '22 09:09

Dimitris Fasarakis Hilliard