提供Python 3.6元类的__classcell__示例 [英] Provide __classcell__ example for Python 3.6 metaclass
问题描述
根据3.6.0文档:
CPython实现细节:在CPython 3.6和更高版本中,
__class__
单元格作为类中的__classcell__
条目传递给元类 命名空间.如果存在,则必须传播到type.__new__
调用以便正确初始化该类.做不到 因此将在Python 3.6中生成DeprecationWarning
,并且RuntimeWarning
将来.
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 thetype.__new__
call in order for the class to be initialized correctly. Failing to do so will result in aDeprecationWarning
in Python 3.6, and aRuntimeWarning
in the future.
有人可以提供一个正确执行此操作的示例吗?
Can someone provide an example of doing this correctly?
实际需要它的例子吗?
推荐答案
如果您使用依赖于类内部的__class__
可用或引用__class__
的super,则会发出警告.
The warning is raised if you use super that relies on __class__
being available or reference __class__
inside the class body.
从本质上讲,这是需要的,如果您定义一个自定义的元类并篡改所获得的名称空间,然后再将其传递给type.__new__
.您需要小心,并始终确保在metaclass.__new__
中将__classcell__
传递给type.__new__
.
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__
.
也就是说,如果您创建了一个要传递的新名称空间,请始终检查是否在创建的原始名称空间中定义了__classcell__
并将其添加:
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)
您在注释中链接的文件实际上是尝试的许多补丁程序中的第一个, issue23722_classcell_reference_validation_v2.diff
是其中的最后一个补丁,来自问题23722 .
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.
可以在对Django进行的拉取请求中看到正确执行此操作的示例使用它来解决Python 3.6中引入的问题:
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)
__classcell__
只是简单地添加到新的名称空间中,然后再传递给type.__new__
.
The __classcell__
is simply added to the new namespace before being passed to type.__new__
.
这篇关于提供Python 3.6元类的__classcell__示例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!