Project

General

Profile

1
# Dictionaries
2

    
3
import itertools
4
import UserDict
5

    
6
def is_dict(value): return hasattr(value, 'keys')
7

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

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

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

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

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

    
64
import util
65

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

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