2016-02-17 5 views
8

を作成する()は、私がthis exampleに遭遇してきた作品:スーパーどのように読む順序付きカウンター

from collections import Counter, OrderedDict 

class OrderedCounter(Counter, OrderedDict): 
    'Counter that remembers the order elements are first seen' 
    def __repr__(self): 
     return '%s(%r)' % (self.__class__.__name__, 
          OrderedDict(self)) 
    def __reduce__(self): 
     return self.__class__, (OrderedDict(self),) 

oc = OrderedCounter('abracadabra') 

はですこれは魔法のようにどのように動作するかを説明することができ誰か?

これもPython documentation

+0

理解できないことについてもう少し具体的にすることはできますか? – mgilson

+0

クラスはCounter、OrderedDictから継承していますが、これらのクラスを組み合わせてOrderedCounterを生成する方法はわかりません。カウンタ?これは私が求めていることを明確にするのに役立ちますか? – Sean

+0

基本的に、経験則として、複数の継承を避けてください(あなたの同僚はあなたにこの方法であなたを殺しません)...(粗いミックスのものは少し異なります) –

答えて

10

OrderedCounterがOrderedDict documentation例として与えられ、そして任意のメソッドをオーバーライドすることなく動作しているに表示される:クラスメソッドが呼び出されると

class OrderedCounter(Counter, OrderedDict): 
    pass 

、Pythonがなければなりません実行する正しい方法を見つけてください。 「メソッド解決順序」またはmroと呼ばれるクラス階層を検索する定義済みの順序があります。 MROは、属性__mro__に格納されます。

OrderedCounter.__mro__ 

(<class '__main__.OrderedCounter'>, <class 'collections.Counter'>, <class 'collections.OrderedDict'>, <class 'dict'>, <class 'object'>) 

OrderedDictのインスタンスが__setitem__()を呼び出して、それが順序でクラスを検索します。OrderedCounter、(それが発見された)CounterOrderedDict。したがって、oc['a'] = 0のようなステートメントは、OrderedDict.__setitem__()を呼び出して終了します。

対照的に、__getitem__は、mroのサブクラスによってオーバーライドされないため、count = oc['a']dict.__getitem__()によって処理されます。

oc = OrderedCounter()  
oc['a'] = 1    # this call uses OrderedDict.__setitem__ 
count = oc['a']   # this call uses dict.__getitem__ 

より興味深い呼び出しシーケンスはCounter.update()が呼び出される、oc.update('foobar').ファーストのような文で発生します。 Counter.update()のコードではself [elem]が使用され、OrderedDict.__setitem__()が呼び出されます。 のコードはとなり、dict.__setitem__()となります。

基本クラスを元に戻すと、元のクラスは元に戻りません。 mroは違っていて、間違ったメソッドが呼び出されるからです。 MROの

class OrderedCounter(OrderedDict, Counter): # <<<== doesn't work 
    pass 

詳細情報は、Python 2.3 documentationで見つけることができます。

関連する問題