Предоставить пример __classcell__ для метакласса Python 3.6
Согласно 3.6.0 документов:
Детали реализации CPython: в CPython 3.6 и более поздних версиях
__class__
ячейка передается метаклассу как__classcell__
запись в пространстве имен класса. Если присутствует, это должно быть распространено доtype.__new__
вызов для того, чтобы класс был правильно инициализирован. Невыполнение этого требования приведет кDeprecationWarning
в Python 3.6, иRuntimeWarning
в будущем.
Может ли кто-нибудь привести пример правильного поведения?
Пример, где это на самом деле нужно?
1 ответ
Предупреждение появляется, если вы используете нулевой аргумент super super().__method__(args)
который опирается на __class__
быть доступным или ссылка __class__
внутри тела класса.
По сути, текст говорит о том, что это необходимо, если вы определяете пользовательский мета-класс и вмешиваетесь в пространство имен, которое получаете, прежде чем передать его в type.__new__
, Вы должны быть осторожны и всегда убедитесь, что вы проходите __classcell__
в type.__new__
в вашем metaclass.__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
это последний патч, выпущенный в выпуске 23722.
Пример того, как сделать это правильно, можно увидеть в запросе на извлечение, сделанном в 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__
,