为 Python 3.6 元类提供 __classcell__ 示例

Provide __classcell__ example for Python 3.6 metaclass

根据 3.6.0 文档:

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.

有人可以提供正确执行此操作的示例吗?

一个实际需要的例子?

如果您使用依赖 __class__ 可用的 super 或在 class 正文中引用 __class__,则会引发警告。

文本实质上说的是,如果您定义自定义元 class 并在将其传递到 type.__new__ 之前篡改您获得的名称空间,则需要这样做。您需要小心并始终确保在 metaclass.__new__.

中将 __classcell__ 传递给 type.__new__

也就是说,如果你创建一个新的花哨的命名空间来传递,总是检查__classcell__是否在创建的原始命名空间中定义并添加它:

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)

您在评论中链接的文件实际上是许多尝试补丁中的第一个,issue23722_classcell_reference_validation_v2.diff is the final patch that made it in, from Issue 23722

可以在 pull request made to Django 中看到正确执行此操作的示例,该示例使用它来修复 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)

__classcell__ 在传递给 type.__new__ 之前只是添加到新的命名空间。