我在SO上遇到过至少两个体面的嵌套字典实现,一个是to use defaultdict,另一个是to subclass dict。
这两种方法对于大多数功能都可以正常工作,除了它们在访问不存在的键值对时都有副作用:它为该键创建空字典,存储和退货。
理想情况下,我希望在尝试访问不存在的密钥时,在不创建条目(例如空字典)的情况下返回None
的实现。这可行吗?
P.S。我知道我们可以通过使用元组作为键来避免嵌套字典,但是这个实现不起作用,因为我需要访问嵌套字典的每个级别的条目集合。
答案 0 :(得分:2)
仅这两项实现,指向普通dict
的实现是在访问不存在的密钥时返回dict
。您想再次恢复它,从而再次使用默认的dict
类型:
>>> example = {}
>>> example['foo']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'foo'
>>> example['foo'] = {}
>>> example['foo']['bar'] = 1
如果您想要返回None而不是dict,那么只需使用defaultdict(lambda: None)
代替:
>>> from collections import defaultdict
>>> example = defaultdict(lambda: None)
>>> example['foo'] is None
True
请注意,你不能双管齐下; Python首先必须找到第一个密钥并将其解析为dict
,然后才能查找第二个密钥:
>>> example['foo']['bar']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'NoneType' object is unsubscriptable
答案 1 :(得分:2)
如果您希望d[key][subkey] = value
使用缺少的密钥,则必须放弃返回无的要求。如果d[key] is None
,d[key][subkey] = value
等同于None[subkey] = value
,则无效。
使用缺失值可以做的是返回一个空的类似dict的对象,而不是将它分配给一个键。如果该对象持有对父对象的引用,则可以延迟赋值,直到在层次结构中有明确的赋值。
一个示例实现(这是不完整的,你必须做的不仅仅是覆盖setitem以拥有一个功能齐全的dict子类):
class NestedDict(dict):
def __init__(self, parent=None, parentkey=None):
self.parent = parent
self.parentkey = parentkey
def __missing__(self, key):
return NestedDict(self, key)
def __setitem__(self, key, value):
if self.parent is not None:
self.parent[self.parentkey] = self
self.parent = None
super(NestedDict, self).__setitem__(key, value)
>>> d = NestedDict()
>>> d[1][2][3] = 4
>>> d[2]
{}
>>> d.keys()
[1]
>>> d[1][2][3]
4
当密钥是元组时,另一种方法是覆盖__getitem__
和__setitem__
来执行嵌套查找。此版本为__getitem__
提供了一个KeyError,用于丢失密钥,以便与常规字典保持一致。如果您愿意,可以轻松更改它以返回None。
class NestedDict(dict):
def __getitem__(self, key):
if isinstance(key, tuple):
try:
x = self
for k in key:
x = x[k]
return x
except (KeyError, TypeError):
raise KeyError(key)
else:
return super(NestedDict, self).__getitem__(key)
def __setitem__(self, key, value):
if isinstance(key, tuple):
d = self
for k in key[:-1]:
d = d.setdefault(k, NestedDict())
d[key[-1]] = value
else:
super(NestedDict, self).__setitem__(key, value)
>>> d = NestedDict()
>>> d[1,2,3] = 4
>>> d[1,2,3]
4
>>> d[1,2,4]
KeyError: (1, 2, 4)
>>> d
{1: {2: {3: 4}}}
答案 2 :(得分:1)
Python支持duck typing用于此类情况:
>>> d={}
>>> d[1]='Some'
>>> try:
... att=d[1]
... except KeyError:
... att=None
...
>>> print att
Some
>>> try:
... att=d[1][2][3]
... except KeyError:
... att=None
...
>>> print att
None
将其转换为类或函数,它应该可以轻松支持我认为您正在寻找的内容。