2016-12-27 13 views
2

согласно 3.6.0 документов:Обеспечить __classcell__ примера для Python 3.6 метакласса

CPython деталь реализации: В CPython 3.6 и более поздних __class__ клетки передаются метакласса как __classcell__ записи в класс пространство имен. Если он присутствует, он должен быть распространен до вызова type.__new__ , чтобы класс был правильно инициализирован. В противном случае приведет к DeprecationWarning в Python 3.6 и RuntimeWarning в будущем.

Может ли кто-нибудь привести пример правильно?

Пример, где это действительно необходимо?

+0

Некоторые идеи: этот патч имеет правильные ключевые слова (я не знаю, если это патч сделал это или нет): http://bugs.python.org/file44533/classcell.patch –

ответ

4

Предупреждение возникает, если вы используете аргумент нуля 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 - последний патч, который сделал его, от 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__.

+0

Мне потребовалось некоторое время, чтобы узнать это создается, если какой-либо метод внутри класса использует форму 'super()'. Это происходит потому, что до того, как было невозможно вызвать какой-либо класс, который использовал бы 'super()' внутри самих методов метакласса. Скорее всего, нужен новый '__init_subclass__' mechansm в Python 3.6. – jsbueno

+0

@jsbueno yup, '__init_subclass__' с пользовательским метаклассом. Если вы используете 'type', вы в порядке. –

+0

@ JimFasarakis-Hilliard вы могли бы предоставить ссылку или простой пример для иллюстрации пользовательского пространства имен? –