具有非平凡默认值的默认字典

Default dict with a non-trivial default

我想创建一个“默认字典”,它对丢失的键执行重要的操作(例如,数据库查找)。我在这里看到了一些旧的答案,比如 Using the key in collections.defaultdict,建议子类化 collections.defaultdict

虽然这是有道理的,但此时是否有理由使用 defaultdict。为什么不简单地继承 dict 并覆盖它的 __missing__ 方法呢? defaultdict 是否提供了我可以通过子类化获得的其他东西?

defaultdict加什么?

根据 the documentationdefaultdict 和内置 dict 之间的唯一区别是:

It overrides one method and adds one writable instance variable.

一个方法__missing__方法,当访问不存在的键时调用。

一个可写实例变量default_factory——一个没有参数的可调用对象,__missing__使用它来确定要使用的默认值缺少钥匙。

大致相当于:

def __missing__(self, key):
    if self.default_factory is None:
        raise KeyError(key)
    self[key] = self.default_factory()
    return self[key]

什么时候继承?

重要的是要明确指出,您甚至需要创建子类的唯一原因是缺少键的默认值 取决于实际键。如果您的默认工厂不需要密钥 - 无论逻辑多么复杂,您都可以 使用 defaultdict 而不是继承。如果 lambda 的逻辑太多了,你当然仍然可以创建一个函数并使用它:

def calc():
    # very long code
    # calculating a static new key
    # (maybe a DB request to fetch the latest record...)
    return new_value

d = defaultdict(calc)

如果你确实需要key本身来计算默认值,那么你需要继承:

何时从 defaultdict 继承?

主要优点是,如果您希望能够拥有一个动态工厂(即在运行时更改 default_factory),这可以让您省去自己实现它的麻烦(无需覆盖 __init__...).

但是,请注意,这意味着您在覆盖 __missing__ 时必须考虑此 default_factory 的存在,如 this answer.[=32 中所示=]

何时从 dict

继承

当您不关心动态更改工厂并且可以满足于整个 dict 存在期间的静态工厂时。

在这种情况下,您只需覆盖 __missing__ 方法并使用依赖于密钥的任何复杂逻辑来实现工厂。