タプルによる辞書アクセスを許可するために、 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