带有过滤数据和条件标志的`dict.popitem`

时间:2013-11-04 23:52:50

标签: python

我正在实现一个使用字典来存储数据的东西。除了普通数据外,它还存储一些内部数据,所有数据都以_为前缀。但是,我想从这个数据中隔离库的用户,因为他通常不关心它。另外,我需要在我的班级中设置一个modified标志来跟踪数据是否被修改。

对于所有接口函数,这很好用,这里有两个例子,一个有一个,一个没有修改。请注意,在这种情况下,我不隐藏内部数据,因为它是有意要求的密钥:

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

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

在某些功能上,例如__iter__,我在生成数据之前过滤掉以_开头的所有内容。

但是单个函数在这里会产生实际问题:popitem。在它的正常行为中,它只会撤回一个任意项并在从dict中删除它时返回它。然而,问题出现了:如果没有深入的内部知识,我不知道事先会返回哪个项目。但我知道popitem遵循与itemskeys相同的规则。所以我确实想出了一个实现:

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')

此实施有效。但它感觉到unpythonic,而不是动态或干净。它也很难提出这样的例外:{}.popitem()看起来非常疯狂,但至少会给我一个动态的方式(例如,如果异常消息或类型发生变化,我不需要调整)。

我现在所追求的是一种更清洁,更少疯狂的方法来解决这个问题。有一种方法可以从字典中删除内部数据,但我只是把这条路作为最后的手段。所以你有任何食谱或想法吗?

3 个答案:

答案 0 :(得分:2)

为您的对象提供两个 dict属性:self._dataself._internal_data。然后将所有dict方法转发到self._data,您不必过滤掉任何内容。

编辑:好的,我最后错过了“最后的手段”。但我怀疑管理两个dicts比“修复”每个单独的dict方法和操作符要容易得多。 :)

答案 1 :(得分:1)

  1. 子类dict而不是包装字典。你需要实现更少的东西。
  2. 将“内部数据”存储为对象的属性,而不是字典中的属性。这样,如果需要它们很容易,但不会出现在普通迭代中。如果在某些时候您需要将它们组合起来,请使用x = dict(self); x.update(self.__dict__)执行此操作以创建具有两组值的新字典。
  3. 如果您确实希望将内部数据存储为字典,请嵌入该字典。在主对象上实现__missing__,这样您就可以从内部字典中获取项目,如果在主要字典中找不到这些项目。

答案 2 :(得分:0)

嗯,逻辑是正确的,你可以把它简化为:

self._data.pop(next((key for key in self._data if not key.startswith('_')), 'popitem(): dictionary is empty'))

因此,找到self._data中不以_开头的下一个键,否则将其默认为不匹配字典中任何其他键的键,以便当pop弹出失败时,你会自动获得KeyError抛出(带有“错误信息”)