我使用嵌套字典作为在实现嵌套字典的最佳方法是什么?上使用实现嵌套字典的最佳方法是什么?类答案实现的方法,即
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['foo']['bar'] = 'spam'从而允许在字典中任意嵌套。是否有一种方法可以修改类,以便使用任意一组键将值分配给成员,但在尝试从成员访问/读取时只允许先前定义的一组键?例如,
print a['foo']['bar']
print a['foo']['eggs']目前产出
spam
{}如果第二个错误给出一个错误,因为‘’foo‘还没有定义,那就太好了。
发布于 2013-08-14 18:09:28
您将遇到的问题是,要在嵌套字典上设置项,首先必须能够获得所有父项。例如:
d[1][2][3] = 42需要获取d[1][2]才能设置d[1][2][3]。当您访问中间字典时,无法知道作业是否正在进行,因此,使赋值工作的唯一方法是始终在访问时创建子字典。(您可以返回某种代理对象,而不是创建子字典,并将中间字典的创建推迟到赋值,但是当您访问不存在的路径时,仍然不会得到错误。)
最简单的方法是使用单个元组键,而不是重复的子键。换句话说,不是设置d[1][2][3],而是设置d[1, 2, 3]。然后,赋值是独立的操作:它们不需要获得任何中间嵌套级别,所以您只能在赋值时创建中间级别。
作为一项奖励,您可能会发现在传递多个键时,使用元组要简单得多,因为您可以将它们插入[]并获取所需的项。
您可以使用单个字典来完成此操作,使用元组作为键。然而,这就失去了数据的层次结构。下面的实现使用了子词典。使用一个名为node的字典子类,以便我们可以在字典上分配一个属性来表示该位置节点的值;这样,我们可以在中间节点和叶子上存储值。(它有一个__repr__方法,它既显示节点的值,也显示它的子节点(如果有)。)__setitem__类的tupledict方法在分配元素时处理创建中间节点。__getitem__遍历节点以找到所需的值。(如果希望将各个节点作为节点访问,可以使用get()一次访问它们。)
class tupledict(dict):
class node(dict):
def __repr__(self):
if self:
if hasattr(self, "value"):
return repr(self.value) + ", " + dict.__repr__(self)
return dict.__repr__(self)
else:
return repr(self.value)
def __init__(self):
pass
def __setitem__(self, key, value):
if not isinstance(key, tuple): # handle single value
key = [key]
d = self
for k in key:
if k not in d:
dict.__setitem__(d, k, self.node())
d = dict.__getitem__(d, k)
d.value = value
def __getitem__(self, key):
if not isinstance(key, tuple):
key = [key]
d = self
for k in key:
try:
d = dict.__getitem__(d, k)
except KeyError:
raise KeyError(key[0] if len(key) == 1 else key)
try:
return d.value
except AttributeError:
raise KeyError(key[0] if len(key) == 1 else key)用法:
td = tupledict()
td['foo', 'bar'] = 'spam'
td['foo', 'eggs'] # KeyError
key = 'foo', 'bar'
td[key] # 'spam'发布于 2013-08-14 16:47:04
我不认为有任何方法来做你想要做的事情,但是如果你对你设置键的方式有一点修改的话,你可以通过使用普通字典得到类似的东西。
def nested_dict_set(d, keys, value):
for k in keys[:-1]:
d = d.setdefault(k, {})
d[keys[-1]] = value
a = {}
nested_dict_set(a, ['foo', 'bar'], 'spam')
print a['foo']['bar']
print a['foo']['eggs'] # raises a KeyError发布于 2022-03-09 11:39:49
让我们从字典开始。。
如果您尝试访问一个不存在的项,您将得到一个键错误。
>>> d = {}
>>> d["a"]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'a'尽管如此,您可以通过设置一个项来使其生动化。
>>> d["a"] = 0
>>> d
{"a": 0}这就是说-对于您的用例-您可能会更好地复制这个模式。让你的对象生动化为项目设置,而不是项目获取。@kindall和@Anrew解决方案是这种方法的两种不同方式,让我提出第三种方法。
NestedDict类
from dataclasses import dataclass
@dataclass
class NestedDict:
ndict: dict
def __getitem__(self, key):
if not isinstance(key, tuple):
key = (key,)
item = self.ndict
for k in key:
item = item[k]
return item
def __setitem__(self, key, value):
if not isinstance(key, tuple):
key = (key,)
item = self.ndict
for k in key[:-1]:
item = item.setdefault(k, {})
item[key[-1]] = value让我们看看这个类的行为。获取不存在的项会引发错误:
>>> nd = NestedDict({})
>>> nd["a"]
Traceback (most recent call last):
File "<stdin>", line 11, in __getitem__
KeyError: 'a'按项创建新项设置
>>> nd["a"] = 0
>>> nd["b", "a"] = 1
>>> nd["b", "b"] = 2
>>> nd
NestedDict(ndict={'a': 0, 'b': {'a': 1, 'b': 2}})ndicts package
如果您是pip install ndicts,则可以免费获得适当的NestedDict类。
from ndicts.ndicts import NestedDict
nd = NestedDict()
nd["a"] = 0
nd["b", "a"] = 1
nd["b", "b"] = 2>>> nd
NestedDict({'a': 0, 'b': {'a': 1, 'b': 2}})https://stackoverflow.com/questions/18237343
复制相似问题