使用经过筛选的数据和条件标记的 `dict.popitem`

我在实现一个使用字典来存储数据的程序。除了普通数据之外,它还存储一些内部数据,所有内部数据都以 _ 为前缀。但是,我希望将库的用户与这些数据隔离开来,因为他们通常不关心这些数据。此外,我需要在我的类中设置一个修改标记,以跟踪数据是否被修改。

对于所有界面函数,这种方法都能很好地工作,这里有两个示例,一个带修改,另一个不带修改。请注意,在这种情况下,我没有隐藏内部数据,因为它是故意作为键而要求的:

def __getitem__(self, key):
    return self._data[key]

def __setitem__(self, key, value):
    self.modified = True
    self._data[key] = value

在一些函数中,例如 iter,我会在产生数据之前过滤掉所有以 _ 开头的数据。

但是有一个函数在这里造成了真正的问题:popitem。在它的正常行为中,它只会撤回一个任意项并将其返回,同时从字典中删除它。然而,问题来了:如果没有深入的内部知识,我事先不知道会返回哪一项。但我知道 popitem 遵循与 items 和 keys 相同的规则。所以我想到一个实现方法:

keys = self._data.keys()
for k in keys:
    if k.startswith("_"):
        continue
    v = self._data.pop(k)
    self.modified = True
    return k, v
else:
    raise KeyError('popitem(): dictionary is empty')

这种实现方法确实可行。但它感觉不符合 Python 的惯例,而且一点也不动态或干净。它也与引发异常的方式作斗争,就像这样:{}.popitem(),这看起来完全疯狂,但至少会给我一种动态的方式(例如,如果异常消息或类型发生变化,我就不必去调整)。

我现在正在寻找一个更干净、更不疯狂的方法来解决这个问题。有一种方法可以从字典中删除内部数据,但我只会把它作为最后的手段。所以你有任何解决这个问题的食谱或想法吗?

解决方案

答案1:

给你的对象两个字典属性:self._data 和 self._internal_data。然后将所有字典方法转发到 self._data,你就不必过滤任何内容了。

class MyDict(dict):
    def __init__(self, data, internal_data):
        self._data = data
        self._internal_data = internal_data

    def __getitem__(self, key):
        return self._data[key]

    def __setitem__(self, key, value):
        self.modified = True
        self._data[key] = value

    # ... and so on for other dict methods

答案2:

继承 dict 而不是包装字典。你将需要实现少得多的东西。

将你的“内部数据”存储为对象上的属性,而不是存储在字典中。这样,如果需要,很容易就能访问它们,但它们不会出现在普通的迭代中。如果你在某个时候需要组合它们,可以使用 x = dict(self); x.update(self.dict) 来创建一个包含两组值的新字典。

如果你确实想将你的内部数据存储为字典,那么就把它嵌入进去。在你主要的对象上实现 missing,这样你就可以从内部字典中抓取项目,如果它们在主要字典中找不到的话。

class MyDict(dict):
    def __init__(self, data, internal_data):
        self._data = data
        self._internal_data = internal_data

    def __getitem__(self, key):
        try:
            return self._data[key]
        except KeyError:
            return self._internal_data[key]

    def __setitem__(self, key, value):
        self.modified = True
        self._data[key] = value

    # ... and so on for other dict methods
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值