13

ネストされた辞書を操作する方法を探しているときに、noskloによって投稿された次のコードを見つけました。説明したいと思います。

class AutoVivification(dict):
    """Implementation of perl's autovivification feature."""
    def __getitem__(self, item):
        try:
            return dict.__getitem__(self, item)
        except KeyError:
            value = self[item] = type(self)()
            return value

テスト:

a = AutoVivification()

a[1][2][3] = 4
a[1][3][3] = 5
a[1][2]['test'] = 6

print a

出力:

{1: {2: {'test': 6, 3: 4}, 3: {3: 5}}}

私はかなり初心者のプログラマーです。私が知っていることのほとんどは、高校時代にターボ パスカルに関する唯一の正式なトレーニングを受けて、サイドで自分の時間に学びました。__init__、クラス メソッドを使用したり、 を使用してクラスのインスタンス内にデータを保存したりするなど、簡単な方法でクラスを使用できることを理解していfoo.man = 'choo'ます。

一連の角括弧がクラスを介して正しく指示される__getitem__方法がわかりません (何らかの方法で呼び出していると思います)。また、メソッドを個別に 3 回呼び出すことなく、それぞれがどのように簡潔に処理されるかがわかりません。

(dict)クラス宣言の は によって処理されるという印象を受けました__init__

私はtry: except:以前にも、非常に単純な方法で使用しました。tryが実行されると、一連の関数が呼び出されているように見えます__getitem__。現在のレベルの辞書が存在する場合、try はパスして次の辞書に移動することがわかりました。except、私が集めると、 があるときに実行されますが、そのように使用されるのKeyErrorは見たことがありませんself。 のインスタンスSelfだと思っていたのに、辞書のように扱われています...両方ですか?このように 2 回続けて代入したことはありませんが、 が を指しているのに対し、 が の結果を指していると思われます。しかし、次のようなものを返します:selfclass AutoVivificationfoo = man = choovalueself[item]self[item]type(self)type(self)<class '__main__.AutoVivification'>そうじゃない?最後にある余分な丸括弧が何のためにあるのかわかりません。関数がどのように呼び出されているのかわからないため、どこvalueに返されているのかわかりません。

質問ばかりですみません!これには理解できないことがたくさんあり、ドキュメントを何時間も読んでいない限り、どこを調べたらよいかわかりません。このコードは私の目的を果たしているように見えますが、使用する前に理解したいと思います。

ネストされた辞書を使用してプログラムで何をしようとしているのか知りたい場合: 天文学的なスケールで地図データを保持しようとしています。4 回ネストされた 10^6 アイテムの辞書/リスト (つまり 10^24 アイテム) を作成することはできませんが、スペースはほとんど空であるため、空の値を完全に除外して、何かがある場合にのみ割り当てることができます。私を悩ませていたのは、辞書を効率的に処理する方法でした。

4

2 に答える 2

19

1行ずつ:

class AutoVivification(dict):

のサブクラスを作成します。dictこれAutoVivificationは一種のでありdict、いくつかのローカルな変更があります。

def __getitem__(self, item):

__getitem()__フックは、誰かが[...]インデックスルックアップを介してインスタンス上のアイテムにアクセスしようとするたびに呼び出されます。したがって、誰かが行うときはいつでもobject[somekey]type(object).__getitem__(object, somekey)と呼ばれます。

try少しスキップします。次の行は次のとおりです。

 return dict.__getitem__(self, item)

これにより、バインドされていないメソッドが呼び出さ__getitem__()れ、キーとともに独自のインスタンスが渡されます。つまり、親クラスで定義されているようにオリジナル を呼び出します。__getitem__dict

itemこれで、辞書にキーがない場合に何が起こるかがわかりました。aが発生しKeyErrorます。ここでtry:except KeyErrorコンボが登場します。

    try:
        return dict.__getitem__(self, item)
    except KeyError:
        value = self[item] = type(self)()
        return value

したがって、現在のインスタンス(のサブタイプdict)に特定のキーがない場合は、元のメソッドがスローするKeyError例外をキャッチし、代わりに新しい値を作成して格納し、その値を返します。dict.__getitem__()self[item]

selfさて、それはの(サブクラス)dictなので、辞書であることを思い出してください。したがって、新しい値を割り当てることができ(ちなみに、__setitem__フックを使用します)、この場合、と同じタイプの新しいselfインスタンスを作成します。それは別のdictサブクラスです。

では、電話をかけるとどうなるのa[1][2][3] = 4でしょうか。Pythonはこのステップバイステップを実行します:

  1. a[1]につながりtype(a).__getitem__(a, 1)ます。のカスタム__getitem__メソッドは、の新しいAutoVivificationインスタンスをKeyError作成し、それをキーの下に格納して返します。AutoVivification1

  2. a[1]空のAutoVivificationインスタンスを返しました。そのオブジェクトに対して次のアイテムアクセス[2]が呼び出され、ステップ1で発生したことを繰り返します。がありKeyError、の新しいインスタンスAutoVivificationが作成され、キーの下に保存され、2その新しいインスタンスが呼び出し元に返されます。

  3. a[1][2]空のAutoVivificationインスタンスを返しました。そのオブジェクトに対して次のアイテムアクセス[3]が呼び出され、ステップ1(およびステップ2)で発生したことを繰り返します。がありKeyError、の新しいインスタンスAutoVivificationが作成され、キーの下に保存され、3その新しいインスタンスが呼び出し元に返されます。

  4. a[1][2][3]空のAutoVivificationインスタンスを返しました。ここで、そのインスタンスに新しい値を格納します4

次のコード行に移動するとa[1][3][3] = 5、最上位のAutoVivificationインスタンスにはすでに1キーがあり、そのreturn dict.__getitem__(self, item)行は対応する値を返します。これは、AutoVivification上記の手順1で作成されたインスタンスです。

そこから、[3]アイテムアクセス呼び出しによって新しいAutoVivificationインスタンスが再度作成され(オブジェクトにa[1]はキーしかないため2)、同じ手順をすべて繰り返します。

于 2012-11-07T19:07:02.400 に答える
2

object.__getitem__手始めに、ドキュメントを参照してください。

class AutoVivification(dict)宣言はのAutoVivificationサブクラスを作成するため、このクラスが をオーバーライドするときのように、何らかの動作を明示的にオーバーライドしない限り、以前とdict同じように動作します。dict__getitem__

への呼び出しdict.__getitem__(self, item)は通常、代わりに次のように記述されます。

super(AutoVivification, self).__getitem__(item)

(少なくとも Python 2.x では、Python 3 の方が構文が優れています。) いずれにせよ、これが行うことは、既定のdict動作を実行させようとすることですが、それが機能しない場合に備えてフォールバックを実装します。

type(self)()最初にselfインスタンスに対応するクラス オブジェクトを検索し、次にクラス オブジェクトを呼び出しますAutoVivification()

それがあなたのためにそれを解決することを願っています!

于 2012-11-07T19:05:31.503 に答える