collections.py
56 lines
| 1.3 KiB
| text/x-python
|
PythonLexer
Jason R. Coombs
|
r51261 | # adapted from jaraco.collections 3.9 | ||
import collections | ||||
class Projection(collections.abc.Mapping): | ||||
""" | ||||
Project a set of keys over a mapping | ||||
>>> sample = {'a': 1, 'b': 2, 'c': 3} | ||||
>>> prj = Projection(['a', 'c', 'd'], sample) | ||||
>>> prj == {'a': 1, 'c': 3} | ||||
True | ||||
Keys should only appear if they were specified and exist in the space. | ||||
>>> sorted(list(prj.keys())) | ||||
['a', 'c'] | ||||
Attempting to access a key not in the projection | ||||
results in a KeyError. | ||||
>>> prj['b'] | ||||
Traceback (most recent call last): | ||||
... | ||||
KeyError: 'b' | ||||
Use the projection to update another dict. | ||||
>>> target = {'a': 2, 'b': 2} | ||||
>>> target.update(prj) | ||||
>>> target == {'a': 1, 'b': 2, 'c': 3} | ||||
True | ||||
Also note that Projection keeps a reference to the original dict, so | ||||
if you modify the original dict, that could modify the Projection. | ||||
>>> del sample['a'] | ||||
>>> dict(prj) | ||||
{'c': 3} | ||||
""" | ||||
def __init__(self, keys, space): | ||||
self._keys = tuple(keys) | ||||
self._space = space | ||||
def __getitem__(self, key): | ||||
if key not in self._keys: | ||||
raise KeyError(key) | ||||
return self._space[key] | ||||
def __iter__(self): | ||||
return iter(set(self._keys).intersection(self._space)) | ||||
def __len__(self): | ||||
return len(tuple(iter(self))) | ||||