1
2 """Contains the ParameterDict class, useful for defining
3 recursive dictionaries of parameters and using attribute
4 syntax for later access.
5
6 Some useful features:
7 - Recursive copy function of parameter subsets
8 - Recursive update function including parameter subsets
9 - Recursive indented pretty-print
10 - Valid parameters are declared as keyword arguments to the constructor,
11 and assigning to indeclared variables is not allowed.
12
13 See help(ParameterDict) for an interactive example.
14 """
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
37 """A dictionary with attribute-style access,
38 that maps attribute access to the real dictionary.
39
40 Interactive example:
41 >>> m = ParameterDict(Re = 1.0, f = "sin(x)")
42 >>> print m
43 Re = 1.0
44 f = 'sin(x)'
45 >>> s = ParameterDict(max_iterations = 10, tolerance = 1e-8)
46 >>> print s
47 max_iterations = 10
48 tolerance = 1e-08
49 >>> p = ParameterDict(model = m, solver = s)
50 >>> print p
51 model = {
52 Re = 1.0
53 f = 'sin(x)'
54 }
55 solver = {
56 max_iterations = 10
57 tolerance = 1e-08
58 }
59 >>> q = p.copy()
60 >>> q.model.Re = 2.3e6
61 >>> q.solver.max_iterations = 100
62 >>> print q
63 model = {
64 Re = 2300000.0
65 f = 'sin(x)'
66 }
67 solver = {
68 max_iterations = 100
69 tolerance = 1e-08
70 }
71 >>> print p
72 model = {
73 Re = 1.0
74 f = 'sin(x)'
75 }
76 solver = {
77 max_iterations = 10
78 tolerance = 1e-08
79 }
80 >>> p.update(q)
81 >>> print p
82 model = {
83 Re = 2300000.0
84 f = 'sin(x)'
85 }
86 solver = {
87 max_iterations = 100
88 tolerance = 1e-08
89 }
90 >>> s.nothere = 123
91 Traceback (most recent call last):
92 File "doctest.py", line 1212, in __run
93 compileflags, 1) in test.globs
94 File "<doctest __main__.ParameterDict[13]>", line 1, in <module>
95 s.nothere = 123
96 File "ParameterDict.py", line 107, in __setattr__
97 raise AttributeError("%s is not an item in this parameter dict." % key)
98 AttributeError: nothere is not an item in this parameter dict.
99 """
101 dict.__init__(self, **params)
102 for k,v in params.iteritems():
103 self.__setattr__(k, v)
104
106 return self.__dict__.items()
107
109 for key, val in items:
110 self.__dict__[key] = val
111
114
116 return "%s(%s)" % (self.__class__.__name__, ", ".join("%s = %s" % (k,repr(dict.__getitem__(self, k))) for k in sorted(dict.iterkeys(self))))
117
120
122 assert isinstance(key, str)
123 if dict.__contains__(self, key):
124 dict.__setitem__(self, key, value)
125 else:
126 raise AttributeError("%s is not an item in this parameter dict." % key)
127 return dict.__setattr__(self, key, value)
128
130 if not dict.__contains__(self, key):
131 raise AttributeError("%s is not an item in this parameter dict." % key)
132 return dict.__getitem__(self, key)
133
149
151 """Make a copy of self, including recursive copying of parameter subsets.
152 Parameter values themselves are not copied."""
153
154 items = {}
155 for k in dict.iterkeys(self):
156 v = getattr(self, k)
157 if isinstance(v, dict):
158 items[k] = v.copy()
159 else:
160 items[k] = v
161 ch = ParameterDict(**items)
162 return ch
163
165 "A recursive update that handles parameter subsets correctly unlike dict.update."
166
167 for k in dict.iterkeys(other):
168 sv = getattr(self, k)
169 ov = getattr(other, k)
170 if isinstance(sv, dict):
171
172 sv.update(ov)
173 else:
174
175 setattr(self, k, ov)
176
177
178
179 if __name__ == "__main__":
180
184
188
190 p = ParameterDict(something = 3,
191 other = .1239,
192 a = default_a(),
193 b = default_b()
194 )
195 return p
196
197
198 p = default_params()
199
200
201 p.something = 9
202 p.other = "8134"
203
204
205 try:
206 p.blatti = 7
207 raise RuntimeError("Failed to throw exception on erroneous parameter assignment.")
208 except:
209 pass
210
211
212 for k in p.keys():
213 print k
214 for k in p.iterkeys():
215 print k
216 for v in p.values():
217 print v
218 for v in p.itervalues():
219 print v
220 for k,v in p.items():
221 print k,v
222 for k,v in p.iteritems():
223 print k,v
224
225
226 ap1 = p.a
227 ap2 = p["a"]
228 assert ap1 is ap2
229
230
231 print
232 print "str(p):"
233 print str(p)
234 print
235 print "repr(p):"
236 print repr(p)
237 print
238
239
240 q = p.copy()
241 q.something = "q specific!"
242 q.a.abla = "q.a specific!"
243 print
244 print "Should be different:"
245 print repr(p)
246 print repr(q)
247
248
249 p.update(q)
250 print
251 print "Should be equal:"
252 print repr(q)
253 print repr(p)
254
255
256 print
257 print q.format()
258
259 print p
260
261
263 import doctest
264 doctest.testmod()
265 if __name__ == "__main__":
266 _test()
267