Python creates its own view of a subset of a dictionary

Since many questions are on the topic here at SO attest, taking a fragment of a dictionary is a fairly common task, with a pretty nice solution:

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

But this creates a new dictionary with its own comparisons. For many operations, it would be nice to just have an unchanged view of the original dict (i.e., it does not support assignment or deletion in the view). An implementation of this type is probably easy, but it is not good to propagate local utility classes.

So my question is: is there a built-in way to get such a "subset"? Or is there a third-party library (preferably accessible through PyPi) that provides a good implementation of such a utility?

+5
source share
3 answers

This is pretty easy to implement:

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)
+4
source

There seems to be no built-in way to get representation in the dictionary. The simplest workaround is the Jochen approach. I adapted his code slightly so that it worked for my purposes:

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}

So d2behaves like a dictionary in all aspects except printing, due to a different method __repr__(). Inheriting from dictto obtain __repr__()will require the re-implementation of each method, as is done for collections.OrderedDict. If only readonly browsing is required, you can inherit from collections.Mappingand save the implementation of __setitem__()and __delitem__(). I find it DictViewuseful to select parameters from self.__dict__and transfer them in a compact form.

+4
source

, - :?

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

If so, then I do not know any such third class. If you want to simplify the implementation of the remaining methods a little, you can use "UserDict" as the base class, which is basically a wrapper for the dict (the attribute "UserDict.data" is used to store the wrapped dict).

+2
source

All Articles