Project

General

Profile

1
# Dictionaries
2

    
3
import itertools
4
import UserDict
5

    
6
import util
7

    
8
def is_dict(value): return hasattr(value, 'keys')
9

    
10
class DictProxy(UserDict.DictMixin):
11
    '''A proxy that forwards all accesses to an inner dict.'''
12
    
13
    def __init__(self, inner): self.inner = inner
14
    
15
    def keys(self): return self.inner.keys()
16
    
17
    def __getitem__(self, key): return self.inner[key]
18
    
19
    def __setitem__(self, key, value): self.inner[key] = value
20

    
21
class IdCompared:
22
    '''A value that's compared using `is` instead of ==.
23
    Do not use this for strings as they are interned, causing `is` to have the
24
    same meaning as ==.
25
    '''
26
    
27
    def __init__(self, value): self.value = value
28
    
29
    def __eq__(self, other):
30
        return (other != None and other.__class__ == self.__class__
31
            and other.value is self.value)
32
    
33
    def __hash__(self): return id(self.value)
34

    
35
class IdDict(dict):
36
    '''A dict that stores objects by id()'''
37
    
38
    def add(self, *values):
39
        for value in values: self[id(value)] = value
40
        return self
41
    
42
    def add_vars(self, vars_): return self.add(*vars_.values())
43

    
44
class MergeDict:
45
    '''A dict that checks each of several dicts'''
46
    
47
    def __init__(self, *dicts): self.dicts = dicts
48
    
49
    def __getitem__(self, key):
50
        for dict_ in self.dicts:
51
            try: return dict_[key]
52
            except KeyError: pass
53
        raise # reraise last KeyError
54

    
55

    
56
class AttrsDictView:
57
    '''A dict view of an object's attributes
58
    @pre If you want __iter__() to work, value must have a __dict__
59
    '''
60
    
61
    def __init__(self, value): self.value = value
62
    
63
    def __iter__(self): return iter(self.value.__dict__)
64
    
65
    def __getitem__(self, key): return getattr(self.value, key)
66

    
67
def make_hashable(value):
68
    if isinstance(value, list): value = tuple(value)
69
    elif isinstance(value, dict): value = util.NamedTuple(**value)
70
    return value
71

    
72
def join(dict0, dict1):
73
    '''Joins dict0 (A->B mapping) to dict1 (B->C mapping) SQL-style.
74
    If a value in dict0 has no key in dict1, uses the value itself.
75
    '''
76
    new_dict = {}
77
    for out, in_ in dict0.iteritems():
78
        new_dict[out] = dict1.get(in_, in_) # use in_ if no match found
79
    return new_dict
(11-11/36)