【问题标题】:Python create own dict view of subset of dictionaryPython创建自己的字典子集的字典视图
【发布时间】:2012-03-08 22:17:27
【问题描述】:

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

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

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

那么,我的问题是:有没有一种内置的方法可以获取这样的“子集视图”?或者是否有第三方库(最好通过 PyPi 获得)可以很好地实现此类实用程序?

【问题讨论】:

  • 我建议字典上的“不可变视图”正是您使用示例代码所获得的......因为没有制作字典的单独副本,我不确定你是怎么做的重新使“不可变”部分工作。
  • @larsks:它根本不支持赋值。
  • @larsks:我假设通过“不可变视图”,OP 意味着视图对象本身没有方法来改变字典(例如 pop),并且对包装的 dict 的任何更改都是立即可见的在视图中。当然,它在“深层”意义上不是不可变的——也就是说,如果你执行 my_view[some_key].append(12),那么对应于 12 的值当然会被修改。

标签: python dictionary facade


【解决方案1】:

似乎没有内置方法可以获取字典视图。最简单的解决方法似乎是 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__() 方法不同。从dict 继承以得到__repr__() 需要重新实现每个方法,就像collections.OrderedDict 所做的那样。如果只想要一个只读视图,可以从collections.Mapping 继承并保存__setitem__()__delitem__() 的实现。我发现DictViewself.__dict__ 中选择参数并以紧凑的形式传递它们很有用。

【讨论】:

    【解决方案2】:

    这很容易实现:

    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)
    

    【讨论】:

    • 是的,这很容易实现,而且看起来不错,但如前所述,很多本地实现和名称并不是一件好事。
    【解决方案3】:

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

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

    【讨论】:

    • 是的,就是这样。
    猜你喜欢
    • 2014-10-02
    • 2019-02-13
    • 2016-07-11
    • 2021-06-25
    • 1970-01-01
    • 2017-05-05
    • 2021-07-07
    • 2018-08-03
    • 2019-08-07
    相关资源
    最近更新 更多