6

正如 SO 上关于该主题的许多问题所证明的那样,取一本字典是一项非常常见的任务,有一个相当不错的解决方案:

{k:v for k,v in dict.viewitems() if some_test(k,v)}

但这会创建一个具有自己映射的新字典。对于许多操作,最好只有原始字典的不可变视图(即它不支持视图上的分配或删除操作)。实现这样的类型可能很容易,但是本地实用程序类的扩散并不好。

所以,我的问题是:是否有一种内置的方式来获得这样的“子集视图”?或者是否有提供此类实用程序的良好实现的第三方库(最好通过 PyPi 获得)?

4

3 回答 3

6

似乎没有内置的方法来获取字典的视图。最简单的解决方法似乎是 Jochen 的方法。我稍微修改了他的代码以使其适合我的目的:

from collections import MutableMapping

class DictView(MutableMapping):
    def __init__(self, source, valid_keys):
        self.source, self.valid_keys = source, valid_keys

    def __getitem__(self, key):
        if key in self.valid_keys:
            return self.source[key]
        else:
            raise KeyError(key)

    def __len__(self):
        return len(self.valid_keys)

    def __iter__(self):
        for key in self.valid_keys:
            yield key

    def __setitem__(self, key, value):
        if key in self.valid_keys:
            self.source[key] = value
        else:
            raise KeyError(key)

    def __delitem__(self, key):
        self.valid_keys.remove(key)

d = dict(a=1, b=2, c=3)
valid_keys = ['a', 'c']
d2 = DictView(d, valid_keys)
d2['a'] = -1  # overwrite element 'a' in source dictionary
print d  # prints {'a': -1, 'c': 3, 'b': 2}

因此d2,由于__repr__()方法不同,除了打印之外,在所有方面都表现得像字典。继承 fromdict到 get__repr__()需要重新实现每个方法,就像collections.OrderedDict. 如果只想要一个只读视图,可以继承collections.Mapping并保存 and 的__setitem__()实现__delitem__()。我发现DictView从中选择参数self.__dict__并以紧凑的形式传递它们很有用。

于 2012-07-19T11:50:40.313 回答
4

这很容易实现:

from collections import Mapping
class FilteredItems(Mapping):
    def __init__(self, source, filter):
        self.source = source
        self.p = filter

    def __getitem__(self, key):
        x = self.source[key]
        if self.p(key,x):
            return key,x
        else:
            raise KeyError(key)


d2 = FilteredItems(d, some_test)
于 2012-02-17T14:13:15.623 回答
2

为了澄清语义,您正在考虑这样的事情:?

class FilteredDictView:
    def __init__(self, base_dict, test):
        self._base_dict = base_dict
        self._test = test
    def __getitem__(self, key):
        value = self._base_dict[key] # might throw KeyError
        if not self._test(key,value):
            throw KeyError(key)
        return value
    # ... implement remaining dict-like-methods ...

如果是这样,那么我不知道有任何这样的第三方类。如果您想让其余方法的实现更容易一些,您可以考虑使用“UserDict”作为基类,它基本上只是 dict 的包装器(“UserDict.data”属性用于存储包装的 dict) .

于 2012-02-17T14:15:29.427 回答