2016-07-30 4 views
1

Я хочу добавить атрибут для каждого класса, созданного метаклассом. Например, когда создается класс с именем C, я хочу добавить атрибут C._C__sup, значением которого является дескриптор super(C).Ошибка Python __super черной магии

Вот что я пробовал:

class Meta(type): 
    def __init__(cls, name, bases, dict): # Not overriding type.__new__ 
     cls.__dict__['_' + name + '__sup'] = super(cls) 
     # Not calling type.__init__; do I need it? 

class C(object): 
    __metaclass__ = Meta 

c = C() 
print c._C__sup 

Это дает мне:

TypeError: Error when calling the metaclass bases 
    'dictproxy' object does not support item assignment 

Некоторые справочная информация:
(Вы не должны читать эту часть)

Вдохновленный по this article, что я делаю пытаемся избежать «жестко прописывать» имя класса при использовании super:

Идеи есть использовать несвязанные супер объекты, как частные атрибутов. Например, в нашем примере, мы могли бы определить частный атрибут __sup в классе C как несвязанный супер объект super(C):

>>> C._C__sup = super(C) 

С этим определением внутри методов синтаксис self.__sup.meth может быть использован в качестве альтернативы до super(C, self).meth. Преимущество заключается в том, что вы избегаете повторения имени класса в синтаксисе вызывающего , поскольку это имя скрыто в механизме переключения частных имен . Создание атрибутов __sup можно скрыть в метаклассе и сделать автоматическим. Итак, все это, похоже, сработало: но фактически это не тот случай.

ответ

2

Использование setattr вместо присваивания cls.__dict__:

class Meta(type): 
    def __init__(cls, name, bases, clsdict): # Not overriding type.__new__ 
     setattr(cls, '_' + name + '__sup', super(cls)) 
     super(Meta, cls).__init__(name, bases, clsdict) 

class C(object): 
    __metaclass__ = Meta 
    def say(self): 
     return 'wow' 

class D(C): 
    def say(self): 
     return 'bow' + self.__sup.say() 

c = C() 
print(c._C__sup) 
# <super: <class 'C'>, <C object>> 
d = D() 
print(d.say()) 

печатает

bowwow 

Кстати, это хорошая идея, чтобы позвонить

 super(Meta, cls).__init__(name, bases, clsdict) 

внутри Meta.__init__, чтобы позволить Meta участвовать в иерархиях классов, которым может понадобиться super для правильного вызова цепочки __init__. Это кажется особенно подходящим, поскольку вы строите метакласс, чтобы помочь с использованием использования super.

 Смежные вопросы

  • Нет связанных вопросов^_^