当前位置: 首页 > 面试题库 >

嵌套字典在设置项目时充当defaultdict,但在获取项目时不充当

呼延晋
2023-03-14
问题内容

我想实现一个具有以下属性的类似dict的数据结构:

from collections import UserDict

class TestDict(UserDict):
    pass

test_dict = TestDict()

# Create empty dictionaries at 'level_1' and 'level_2' and insert 'Hello' at the 'level_3' key.
test_dict['level_1']['level_2']['level_3'] = 'Hello'

>>> test_dict
{
    'level_1': {
        'level_2': {
            'level_3': 'Hello'
        }
    }
}

# However, this should not return an empty dictionary but raise a KeyError.
>>> test_dict['unknown_key']
KeyError: 'unknown_key'

据我所知,问题在于python不知道__getitem__是在设置项目的上下文中(即第一个示例)还是在获取和项目的上下文中(第二个示例)调用了。

我已经看过Python的“defaultdict”:设置时使用default,但获取时不使用default,但我不认为这个问题是重复的,也不是它回答了我的问题。

如果您有任何想法请告诉我。

提前致谢。

编辑:

使用以下方法可以实现类似的目的:

def set_nested_item(dict_in: Union[dict, TestDict], value, keys):
    for i, key in enumerate(keys):
        is_last = i == (len(keys) - 1)
        if is_last:
            dict_in[key] = value
        else:
            if key not in dict_in:
                dict_in[key] = {}
            else:
                if not isinstance(dict_in[key], (dict, TestDict)):
                    dict_in[key] = {}

            dict_in[key] = set_nested_item(dict_in[key], value, keys[(i + 1):])
        return dict_in


class TestDict(UserDict):
    def __init__(self):
        super().__init__()

    def __setitem__(self, key, value):
        if isinstance(key, list):
            self.update(set_nested_item(self, value, key))
        else:
            super().__setitem__(key, value)

test_dict[['level_1', 'level_2', 'level_3']] = 'Hello'
>>> test_dict
{
    'level_1': {
        'level_2': {
            'level_3': 'Hello'
        }
    }
}

问题答案:

不可能。

test_dict['level_1']['level_2']['level_3'] = 'Hello'

在语义上等效于:

temp1 = test_dict['level_1'] # Should this line fail?
temp1['level_2']['level_3'] = 'Hello'

但是…如果确定要实现它,则可以检查Python堆栈以获取/解析代码调用行,然后根据代码调用行是否包含分配来改变行为!不幸的是,有时调用代码在堆栈跟踪中不可用(例如,以交互方式调用时),在这种情况下,您需要使用Python字节码。

import dis
import inspect
from collections import UserDict

def get_opcodes(code_object, lineno):
    """Utility function to extract Python VM opcodes for line of code"""
    line_ops = []
    instructions = dis.get_instructions(code_object).__iter__()
    for instruction in instructions:
        if instruction.starts_line == lineno:
            # found start of our line
            line_ops.append(instruction.opcode)
            break
    for instruction in instructions:
        if not instruction.starts_line:
            line_ops.append(instruction.opcode)
        else:
            # start of next line
            break
    return line_ops

class TestDict(UserDict):
    def __getitem__(self, key):
        try:
            return super().__getitem__(key)
        except KeyError:
            # inspect the stack to get calling line of code
            frame = inspect.stack()[1].frame
            opcodes = get_opcodes(frame.f_code, frame.f_lineno)
            # STORE_SUBSCR is Python opcode for TOS1[TOS] = TOS2
            if dis.opmap['STORE_SUBSCR'] in opcodes:
                # calling line of code contains a dict/array assignment
                default = TestDict()
                super().__setitem__(key, default)
                return default
            else:
                raise

test_dict = TestDict()
test_dict['level_1']['level_2']['level_3'] = 'Hello'
print(test_dict)
# {'level_1': {'level_2': {'level_3': 'Hello'}}}

test_dict['unknown_key']
# KeyError: 'unknown_key'

以上只是部分解决方案。如果同一行上还有其他字典/数组分配,仍然可以上当,例如other['key'] = test_dict['unknown_key']。一个更完整的解决方案将需要实际分析代码行以找出变量在赋值中的位置。



 类似资料:
  • 问题内容: 按值从字典中删除某项的最佳方法是什么,即当该项的键未知时?这是一个简单的方法: 有更好的方法吗?迭代字典时从字典中进行变异(删除项目)有什么问题吗? 问题答案: 请注意,您当前正在测试对象的身份(仅当两个操作数由内存中的同一对象表示时才返回- 与相等的两个对象并不总是这样)。如果您故意这样做,则可以将代码重写为 但这可能无法满足您的要求: 因此,您可能想要代替。

  • 我正在尝试将使用此查询和值加载到映射中 查询给了我以下值: 1,0|2,1|3,1|4,2|... 然后我尝试将其加载到vaadin网格中,如下所示: 我不能用动态生成的列和一个可编辑的行加载网格,这些列下面有值。我试图使网格看起来像以下: 我试图遵循以下两个链接,但没有成功: > 如何使用地图项目类型填充Vaadin网格 https://vaadin.com/forum/thread/16038

  • 是否有办法将GradleJava项目导入IntelliJ 2017.2. x并应用一些设置,例如 代码样式 vcs设置 从Gradle在项目层面? 我注意到例如Grails框架使用了idea-gradle-plugin,但这只能与Gradle任务结合使用。 我不想使用Gradle任务生成IntelliJ项目文件。每当我导入文件。 这可能吗?

  • 目前正在练习使用android studio制作应用程序。我有这个自定义字体,并保存到res/font目录中供以后使用。在活动中,我试图使用typeface对象调用getfont(R.font.my\u customized\u font)。例如)Typeface font=getResources()。getfont(R.font.mycustomizedfont) 但是,当我尝试使用API级别

  • 问题内容: 在Python上进行迭代时从字典中删除项目是否合法? 例如: 这个想法是从字典中删除不满足特定条件的元素,而不是创建一个新字典,该字典是正在迭代的字典的子集。 这是一个好的解决方案吗?有没有更优雅/更有效的方法? 问题答案: 此答案不适用于,并且会给出。 :字典在迭代过程中更改了大小。 发生这种情况是因为返回的是迭代器而不是列表。正如评论中指出的那样,只需将其转换为列表即可,它应该可以

  • 问题内容: 在Python上进行迭代时从字典中删除项目是否合法? 例如: 这个想法是从字典中删除不满足特定条件的元素,而不是创建一个新字典,该字典是正在迭代的字典的子集。 这是一个好的解决方案吗?有没有更优雅/更有效的方法? 问题答案: 此答案不适用于,并且会给出。 :字典在迭代过程中更改了大小。 发生这种情况是因为返回的是迭代器而不是列表。正如评论中指出的那样,只需将其转换为列表即可,它应该可以

  • 我设计了一个带有地图片段和回收器视图的布局。每个回收器视图项都是cardview(我已经指定了xml布局)。 问题是RecyclerView项无法填满屏幕宽度。 我尝试将layout_width更改为,…但这没有帮助 下面是每个项目的布局 和main_layout 希望任何人都能帮助我。我被困了三天。非常感谢。 ====~=======:===>====1====2===]====3====0.=

  • 我在尝试运行“cordova platform add android”时收到此错误消息: "错误:请安装Android Target 19(Android最新SDK).确保你有最新的Android工具安装以及。从你的通信和在线运行“Android”来安装/更新任何丢失的SDK或工具。" 但是,我已经安装了SDK(SDK工具23.0.2,SDK平台工具20,SDK构建工具19.1)。我的ANDRO