为 Python 3.6 元类提供 __classcell__ 示例
Posted
技术标签:
【中文标题】为 Python 3.6 元类提供 __classcell__ 示例【英文标题】:Provide __classcell__ example for Python 3.6 metaclass 【发布时间】:2017-05-11 15:04:09 【问题描述】:根据 3.6.0 文档:
CPython 实现细节:在 CPython 3.6 及更高版本中,
__class__
单元格作为类中的__classcell__
条目传递给元类 命名空间。如果存在,则必须将其传播到type.__new__
调用以便正确初始化类。没有做 所以会在 Python 3.6 中产生一个DeprecationWarning
,以及一个RuntimeWarning
未来。
有人可以提供一个正确执行此操作的示例吗?
实际需要的示例?
【问题讨论】:
一些想法:这个补丁有正确的关键词(我不知道这个补丁是否成功):bugs.python.org/file44533/classcell.patch 【参考方案1】:如果您使用依赖于 __class__
可用的 super 或在类主体内引用 __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
是最后一个补丁,来自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__
之前只是添加到新命名空间。
【讨论】:
我花了一段时间才发现如果类中的任何方法使用super()
形式,它就会被创建。这很可能是因为之前不可能调用任何在元类方法本身中使用super()
的类方法。更有可能的是,Python 3.6 中的新 __init_subclass__
机制需要它。
@jsbueno 是的,__init_subclass__
带有自定义元类。如果你使用type
就可以了。
@JimFasarakis-Hilliard 能否提供参考或简单示例来说明自定义命名空间?以上是关于为 Python 3.6 元类提供 __classcell__ 示例的主要内容,如果未能解决你的问题,请参考以下文章