Pythonで複数のレベルの 'collection.defaultdict'


Answers

pickleableでネストされたdefaultdictを作成する別の方法は、ラムダの代わりに部分オブジェクトを使うことです:

from functools import partial
...
d = defaultdict(partial(defaultdict, int))

これは、defaultdictクラスがモジュールレベルでグローバルにアクセス可能であるため機能します:

"ラップする関数(またはこの場合はクラス)がグローバルにアクセス可能でない限り、__name__(__module__内)" - Picklingが部分関数をラップしていない限り、部分オブジェクトをpickleできません

Question

SO上の素晴らしい人たちのおかげで、私はcollections.defaultdictによって提供される可能性を発見しました。特に可読性とスピードが向上しました。 私はそれらを成功に使うようにしました。

今私は3つのレベルの辞書を実装したいと思います.2つの上位のものはdefaultdictあり、最低のものはintです。 私はこれを行う適切な方法を見つけることはありません。 ここに私の試みです:

from collections import defaultdict
d = defaultdict(defaultdict)
a = [("key1", {"a1":22, "a2":33}),
     ("key2", {"a1":32, "a2":55}),
     ("key3", {"a1":43, "a2":44})]
for i in a:
    d[i[0]] = i[1]

これはうまくいきますが、望ましい動作である以下はそうではありません:

d["key4"]["a1"] + 1

私は、第2レベルのdefaultdictint型であると宣言してdefaultdictたいはずだと思うが、どこで、どのようにして行うのか分からなかった。

私が最初にdefaultdictを使用しているのは、新しいキーごとに辞書を初期化する必要がないためです。

それ以上の優雅な提案?

ありがとう!




@ rschwiebのD['key'] += 1に対する要求__add____add__メソッドを定義して追加をオーバーライドすることで、これまでよりもcollections.Counter()ように動作させることができます。

最初の__missing__が呼び出されて新しい空の値が作成され、 __add__に渡され__add__ 。 値をテストし、空の値を数えるとFalseます。

オーバーライドの詳細については、数値型のエミュレートを参照してください。

from numbers import Number


class autovivify(dict):
    def __missing__(self, key):
        value = self[key] = type(self)()
        return value

    def __add__(self, x):
        """ override addition for numeric types when self is empty """
        if not self and isinstance(x, Number):
            return x
        raise ValueError

    def __sub__(self, x):
        if not self and isinstance(x, Number):
            return -1 * x
        raise ValueError

例:

>>> import autovivify
>>> a = autovivify.autovivify()
>>> a
{}
>>> a[2]
{}
>>> a
{2: {}}
>>> a[4] += 1
>>> a[5][3][2] -= 1
>>> a
{2: {}, 4: 1, 5: {3: {2: -1}}}

引数を検査するのではなく、数値(非常に非Python、amirite!)では、デフォルトの0の値を指定して操作を試みることができます。

class av2(dict):
    def __missing__(self, key):
        value = self[key] = type(self)()
        return value

    def __add__(self, x):
        """ override addition when self is empty """
        if not self:
            return 0 + x
        raise ValueError

    def __sub__(self, x):
        """ override subtraction when self is empty """
        if not self:
            return 0 - x
        raise ValueError



Links