You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

修改Python字典默认行为:实现重复键存值、pop删旧值需重写哪些方法?

实现堆叠式字典所需重写的dict方法

嘿,这个需求挺实用的——要做一个「赋值不覆盖旧值、而是把值堆叠成列表,pop时删除最早存入项」的字典对吧?结合你已经了解的方法,我来详细梳理下需要重写的核心方法,以及每个方法的作用:

必须重写的核心方法

  • __setitem__(self, key, value)
    这是实现「值堆叠」的核心,因为当你执行dict[key] = value时,底层调用的就是这个方法。默认的dict.__setitem__会直接覆盖旧值,我们需要修改它的逻辑:

    • 如果key已经存在,就把新value追加到对应的列表中;
    • 如果key不存在,就创建一个包含该value的列表作为key对应的值。
  • pop(self, key, default=None)
    默认的pop会删除整个key并返回对应值,我们需要适配堆叠逻辑:

    • 先获取key对应的列表,弹出列表的第一个元素(也就是最早存入的值);
    • 如果弹出后列表为空,就把这个key从字典中彻底删除;
    • 如果key不存在,要么返回传入的default,要么抛出KeyError(和原生dict的行为保持一致)。

建议补充重写的方法

为了让自定义字典的行为更贴合原生dict的使用场景,还需要重写以下两个方法:

  • __init__(self, *args, **kwargs)
    当用户用初始数据(比如StackedDict(a=1, b=2)或者StackedDict({"a":1}))初始化字典时,默认的__init__会把值存成单个元素,而不是列表。我们需要重写它,将每个初始值都包装成列表,确保后续的堆叠逻辑能正常工作。

  • update(self, other=None, **kwargs)
    原生的update方法会直接覆盖已有键的值,我们需要修改它的逻辑,让它和__setitem__保持一致:把要更新的每个值都追加到对应key的列表中,而不是覆盖。

示例实现代码

class StackedDict(dict):
    def __setitem__(self, key, value):
        if key in self:
            self[key].append(value)
        else:
            super().__setitem__(key, [value])
    
    def pop(self, key, default=None):
        try:
            values = super().__getitem__(key)
            popped_value = values.pop(0)
            # 列表为空时删除key
            if not values:
                super().__delitem__(key)
            return popped_value
        except KeyError:
            if default is not None:
                return default
            # 保持原生dict的异常行为
            raise
    
    def __init__(self, *args, **kwargs):
        super().__init__()
        # 处理位置参数(如传入另一个字典)
        if args:
            for k, v in args[0].items():
                self[k] = v
        # 处理关键字参数
        for k, v in kwargs.items():
            self[k] = v
    
    def update(self, other=None, **kwargs):
        if other is not None:
            for k, v in other.items():
                self[k] = v
        for k, v in kwargs.items():
            self[k] = v

测试示例

sd = StackedDict(a=1)
sd["a"] = 2
sd["a"] = 3
print(sd["a"])  # 输出: [1, 2, 3]
print(sd.pop("a"))  # 输出: 1(最早存入的值)
print(sd["a"])  # 输出: [2, 3]
sd.pop("a")
sd.pop("a")
print("a" in sd)  # 输出: False(列表为空后key被删除)

至于你提到的__getitem__、__iter__、__missing__,如果没有特殊需求(比如改变取值逻辑、迭代方式),不需要重写——原生的行为已经能满足这个堆叠字典的需求。

内容的提问来源于stack exchange,提问作者CodeQuestor

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 07:14:24