2016-07-30 13 views
1

メタクラスで作成されたすべてのクラスに属性を追加します。たとえば、Cという名前のクラスが作成されたときに、その値が記述子super(C)である属性C._C__supを追加したいとします。ここでPython __super black magicが失敗しました

は、私が試したものです:

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を使用するときに「ハードコーディング」クラス名を避けるためにしようとしている:

アイデアはプライベート 属性として結合していないスーパーのオブジェクトを使用することがあります。構文self.__sup.meth が代替として使用できるメソッド内でこの定義により

>>> C._C__sup = super(C) 

:たとえば、私たちの例では、我々は結合していないスーパーのオブジェクト super(C)としてクラスCにプライベート 属性__supを定義することができます〜super(C, self).meth。 の利点は、呼び出し元の 構文でクラスの名前を繰り返さないようにすることです。その名前は、 の名前のマージメカニズムで隠されているためです。 __sup属性の作成は、 メタクラスで非表示にして自動化することができます。だから、これはうまくいくようです:しかし、 実際にはそうではありません。

答えて

2

代わりcls.__dict__への割り当ての使用setattr

ところで
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) 
012を呼び出すことは良いアイデアです

inside Meta.__init__Metaががのチェーンを正しく呼び出すためにsuperを必要とする可能性のあるクラス階層に参加できるようにします。これは、 の の使用を支援するメタクラスを作成しているので、特に適切です。superです。

関連する問題