2016-07-30 44 views
1

Ich möchte ein Attribut für jede Klasse hinzufügen, die von einer Metaklasse erstellt wurde. Wenn beispielsweise eine Klasse mit dem Namen C erstellt wird, möchte ich ein Attribut C._C__sup hinzufügen, dessen Wert der Deskriptor super(C) ist. HierPython __super black magic ist fehlgeschlagen

ist, was ich versucht habe:

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 

Das gibt mir:

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

Einige Hintergrundinformationen:
(Sie nicht, diesen Teil lesen)

Inspiriert von this article, was ich tue versucht, „Hardcoding“ den Klassennamen zu vermeiden, wenn super mit:

Die Idee gibt es die ungebundenen Super Objekte als private Attribute zu verwenden ist.

>>> C._C__sup = super(C) 

Mit dieser Definition in den Methoden die Syntax self.__sup.meth kann als Alternative verwendet werden: Zum Beispiel in unserem Beispiel könnten wir das private Attribut __sup in der Klasse C als ungebundenes Super Objekt super(C) definieren zu super(C, self).meth. Der Vorteil ist, dass Sie vermeiden, den Namen der Klasse in der aufrufenden Syntax zu wiederholen, da dieser Name im Mangelmechanismus von privaten Namen versteckt ist. Die Attribute __sup können in einer Metaklasse versteckt und automatisch gemacht werden. Also, das scheint zu funktionieren: aber eigentlich ist das nicht der Fall.

Antwort

2

Verwenden setattr statt Zuordnung zu 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()) 

druckt

bowwow 

By the way, ist es eine gute Idee

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

innerhalb Meta.__init__ zu ermöglichen, Meta an Klassenhierarchien teilnehmen, die müssen möglicherweise super, um ordnungsgemäß eine Kette von __init__ s anrufen. Dies scheint besonders geeignet, da Sie eine Metaklasse erstellen, um mit der Verwendung von super zu unterstützen.