我在 SO 上遇到过至少两种体面的嵌套字典实现,一种是使用 defaultdict,另一种是子类化 dict。
这两种方法都适用于大多数功能,除了它们在访问不存在的键值对时都有副作用:它为该键创建一个空字典,存储并返回它。
理想情况下,我想要一个None
在尝试访问不存在的键时返回而不创建条目(例如空字典)的实现。这可行吗?
ps 我知道我们可以通过使用元组作为键来避免嵌套字典,但是这个实现对我不起作用,因为我需要访问嵌套字典每个级别的条目集合。
我在 SO 上遇到过至少两种体面的嵌套字典实现,一种是使用 defaultdict,另一种是子类化 dict。
这两种方法都适用于大多数功能,除了它们在访问不存在的键值对时都有副作用:它为该键创建一个空字典,存储并返回它。
理想情况下,我想要一个None
在尝试访问不存在的键时返回而不创建条目(例如空字典)的实现。这可行吗?
ps 我知道我们可以通过使用元组作为键来避免嵌套字典,但是这个实现对我不起作用,因为我需要访问嵌套字典每个级别的条目集合。
您指向的两个实现对普通s 所做的唯一一件事就是在访问不存在的密钥时dict
返回 a 。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 首先必须找到第一个键并将其解析为 adict
才能查找第二个键:
>>> example['foo']['bar']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'NoneType' object is unsubscriptable
d[key][subkey] = value
如果您希望使用丢失的键,您必须放弃返回 None 的要求。如果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 以与常规 dict 保持一致。如果您愿意,您可以轻松地将其更改为返回 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}}}
对于这种情况,Python 支持鸭子类型:
>>> 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
将它放入一个类或一个函数中,它应该很容易支持我认为你正在寻找的东西。