5

タプルによる辞書アクセスを許可するために、 noskloから の以前の回答で与えられた自動有効化のを拡張したいと思います。

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}}}

添え字の任意のタプルを指定してノードを設定したい場合があります。タプルの深さが何層になるかわからない場合、適切なノードを設定する方法をどのように設計すればよいでしょうか?

おそらく、次のような構文を使用できると考えています。

mytuple = (1,2,3)
a[mytuple] = 4

しかし、機能する実装を思い付くのに苦労しています。


アップデート

@JCashの回答に基づいた完全に機能する例があります:

class NestedDict(dict):
    """                                                                       
    Nested dictionary of arbitrary depth with autovivification.               

    Allows data access via extended slice notation.                           
    """
    def __getitem__(self, keys):
        # Let's assume *keys* is a list or tuple.                             
        if not isinstance(keys, basestring):
            try:
                node = self
                for key in keys:
                    node = dict.__getitem__(node, key)
                return node
            except TypeError:
            # *keys* is not a list or tuple.                              
                pass
        try:
            return dict.__getitem__(self, keys)
        except KeyError:
            raise KeyError(keys)
    def __setitem__(self, keys, value):
        # Let's assume *keys* is a list or tuple.                             
        if not isinstance(keys, basestring):
            try:
                node = self
                for key in keys[:-1]:
                    try:
                        node = dict.__getitem__(node, key)
                    except KeyError:
                        node[key] = type(self)()
                        node = node[key]
                return dict.__setitem__(node, keys[-1], value)
            except TypeError:
                # *keys* is not a list or tuple.                              
                pass
        dict.__setitem__(self, keys, value)

拡張スライス表記を使用して、上記と同じ出力を実現できます。

d = NestedDict()
d[1,2,3] = 4
d[1,3,3] = 5
d[1,2,'test'] = 6
4

1 に答える 1

5

これはうまくいくようです

def __setitem__(self, key, value):
    if isinstance(key, tuple):
        node = self
        for i in key[:-1]:
            try:
                node = dict.__getitem__(node, i)
            except KeyError:
                node = node[i] = type(self)()
        return dict.__setitem__(node, i, value)
    return dict.__setitem__(self, key, value)
于 2013-02-25T23:09:34.447 に答える