首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >访问不存在密钥时出现错误的python中的嵌套字典

访问不存在密钥时出现错误的python中的嵌套字典
EN

Stack Overflow用户
提问于 2013-08-14 16:34:08
回答 3查看 1.9K关注 0票数 2

我使用嵌套字典作为在实现嵌套字典的最佳方法是什么?上使用实现嵌套字典的最佳方法是什么?类答案实现的方法,即

代码语言:javascript
复制
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'

从而允许在字典中任意嵌套。是否有一种方法可以修改类,以便使用任意一组键将值分配给成员,但在尝试从成员访问/读取时只允许先前定义的一组键?例如,

代码语言:javascript
复制
print a['foo']['bar']
print a['foo']['eggs']

目前产出

代码语言:javascript
复制
spam
{}

如果第二个错误给出一个错误,因为‘’foo‘还没有定义,那就太好了。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2013-08-14 18:09:28

您将遇到的问题是,要在嵌套字典上设置项,首先必须能够获得所有父项。例如:

代码语言:javascript
复制
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()一次访问它们。)

代码语言:javascript
复制
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)

用法:

代码语言:javascript
复制
td = tupledict()
td['foo', 'bar'] = 'spam'
td['foo', 'eggs']   # KeyError

key = 'foo', 'bar'
td[key]    # 'spam'
票数 3
EN

Stack Overflow用户

发布于 2013-08-14 16:47:04

我不认为有任何方法来做你想要做的事情,但是如果你对你设置键的方式有一点修改的话,你可以通过使用普通字典得到类似的东西。

代码语言:javascript
复制
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
票数 1
EN

Stack Overflow用户

发布于 2022-03-09 11:39:49

让我们从字典开始。

如果您尝试访问一个不存在的项,您将得到一个键错误。

代码语言:javascript
复制
>>> d = {}
>>> d["a"]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'a'

尽管如此,您可以通过设置一个项来使其生动化。

代码语言:javascript
复制
>>> d["a"] = 0
>>> d
{"a": 0}

这就是说-对于您的用例-您可能会更好地复制这个模式。让你的对象生动化为项目设置,而不是项目获取。@kindall和@Anrew解决方案是这种方法的两种不同方式,让我提出第三种方法。

NestedDict类

代码语言:javascript
复制
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

让我们看看这个类的行为。获取不存在的项会引发错误:

代码语言:javascript
复制
>>> nd = NestedDict({})
>>> nd["a"]
Traceback (most recent call last):
  File "<stdin>", line 11, in __getitem__
KeyError: 'a'

按项创建新项设置

代码语言:javascript
复制
>>> 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类。

代码语言:javascript
复制
from ndicts.ndicts import NestedDict

nd = NestedDict()
nd["a"] = 0
nd["b", "a"] = 1
nd["b", "b"] = 2
代码语言:javascript
复制
>>> nd
NestedDict({'a': 0, 'b': {'a': 1, 'b': 2}})
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/18237343

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档