11import inspect
22import json
33import threading
4-
5- from typing import Any , Dict , Set
6- from typing import Callable
4+ from typing import Any , Callable , Dict , Set
75
86_read_tracker : Set [str ] = set ()
97_write_tracker : Set [str ] = set ()
@@ -204,16 +202,12 @@ def dynamic_dispatch(func, name=None, index=None):
204202
205203
206204class HyperParameter (dict ):
207- """
208- HyperParameter is an extended dict with features for better parameter management.
205+ """HyperParameter is an extended dict with features for better parameter management.
209206
210- A HyperParameter can be created with:
207+ Examples
208+ --------
211209 >>> hp = HyperParameter(param1=1, param2=2, obj1={'propA': 'A'})
212210
213- or
214-
215- >>> hp = HyperParameter(**{'param1': 1, 'param2': 2, 'obj1': {'propA': 'A'}})
216-
217211 Once the HyperParameter object is created, you can access the values using the object-style api:
218212 >>> hp.param1
219213 1
@@ -228,16 +222,6 @@ class HyperParameter(dict):
228222
229223 The object-style api also support creating or updating the parameters:
230224 >>> hp.a.b.c = 1
231-
232- which avoid maintaining the dict data manually like this:
233- >>> hp = {}
234- >>> if 'a' not in hp: hp['a'] = {}
235- >>> if 'b' not in hp['a']: hp['a']['b'] = {}
236- >>> hp['a']['b']['c'] = 1
237-
238- You can also create a parameter with a string name:
239- >>> hp = HyperParameter()
240- >>> hp.put('a.b.c', 1)
241225 """
242226
243227 def __init__ (self , ** kws ):
@@ -255,24 +239,29 @@ def update(self, kws):
255239 v = HyperParameter (** v )
256240 self [k ] = v
257241
258- def put (self , name : str , value : Any ):
259- """
260- put/update a parameter with a string name
242+ def put (self , name : str , value : Any ) -> None :
243+ """create or update the parameter with the given `name`
261244
262- Args:
263- name (str): parameter name, 'obj.prop' is supported
264- value (Any): parameter value
245+ Parameters
246+ ----------
247+ name : str
248+ parameter name, 'obj.prop' is supported
249+ value : Any
250+ parameter value
265251
266- Examples:
252+ Examples
253+ --------
267254 >>> cfg = HyperParameter()
268255 >>> cfg.put('param1', 1)
269256 >>> cfg.put('obj1.propA', 'A')
270257
271258 >>> cfg.param1
272259 1
260+
273261 >>> cfg.obj1.propA
274262 'A'
275263 """
264+
276265 path = name .split ("." )
277266 obj = self
278267 for p in path [:- 1 ]:
@@ -282,22 +271,27 @@ def put(self, name: str, value: Any):
282271 obj [path [- 1 ]] = safe_numeric (value )
283272
284273 def get (self , name : str ) -> Any :
285- """
286- get a parameter by a string name
274+ """get the parameter with the given name
287275
288- Args:
289- name (str): parameter name
276+ Parameters
277+ ----------
278+ name : str
279+ parameter name
290280
291- Returns:
292- Any: parameter value
281+ Returns
282+ -------
283+ Any
284+ parameter value
293285
294- Examples:
286+ Examples
287+ --------
295288 >>> cfg = HyperParameter(a=1, b = {'c':2, 'd': 3})
296289 >>> cfg.get('a')
297290 1
298291 >>> cfg.get('b.c')
299292 2
300293 """
294+
301295 path = name .split ("." )
302296 obj = self
303297 for p in path [:- 1 ]:
@@ -306,20 +300,36 @@ def get(self, name: str) -> Any:
306300 obj = obj [p ]
307301 return obj [path [- 1 ]] if path [- 1 ] in obj else _Accessor (self , name )
308302
309- def __setitem__ (self , key , value ):
310- """
311- set value and convert the value into `HyperParameter` if necessary
303+ def __setitem__ (self , key : str , value : Any ) -> None :
304+ """set value and convert the value into `HyperParameter` if necessary
305+
306+ Parameters
307+ ----------
308+ key : str
309+ parameter name
310+ value : Any
311+ parameter value
312312 """
313+
313314 if isinstance (value , dict ):
314315 return dict .__setitem__ (self , key , HyperParameter (** value ))
315316 return dict .__setitem__ (self , key , value )
316317
317- def __getattr__ (self , name ):
318- """
319- read parameter with object-style api
318+ def __getattr__ (self , name : str ) -> Any :
319+ """read parameter with object-style api
320+
321+ Parameters
322+ ----------
323+ name : str
324+ parameter name
320325
321- Examples:
326+ Returns
327+ -------
328+ Any
329+ parameter value
322330
331+ Examples
332+ --------
323333 for simple parameters:
324334 >>> hp = HyperParameter(a=1, b = {'c':2, 'd': 3})
325335 >>> hp.a
@@ -333,18 +343,19 @@ def __getattr__(self, name):
333343 2
334344 """
335345 return self .get (name )
336- # if name in self.keys():
337- # return self[name]
338- # else:
339- # if name in self.__dict__.keys():
340- # return self.__dict__[name]
341- # return _Accessor(self, name)
342-
343- def __setattr__ (self , name , value ):
344- """
345- create/update parameter with object-style api
346346
347- Examples:
347+ def __setattr__ (self , name : str , value : Any ) -> None :
348+ """create/update parameter with object-style api
349+
350+ Parameters
351+ ----------
352+ name : str
353+ parameter name
354+ value : Any
355+ parameter value
356+
357+ Examples
358+ --------
348359 >>> hp = HyperParameter(a=1, b = {'c':2, 'd': 3})
349360 >>> hp.e = 4
350361
@@ -356,69 +367,47 @@ def __setattr__(self, name, value):
356367 1
357368 """
358369 self .put (name , value )
359- # self[name] = value
360370
361371 def __call__ (self ) -> Any :
362- """
363- Return a parameter accessor.
372+ """Return a parameter accessor.
364373
365- Returns:
366- Any: holder of the current parameter
374+ Returns
375+ -------
376+ Any
377+ accessor of the current parameter
367378
368- Examples:
379+ Examples
380+ --------
369381 >>> cfg = HyperParameter(a=1, b = {'c':2, 'd': 3})
370382 >>> cfg().a.get_or_else('default') # default value for simple parameter
371383 1
384+
372385 >>> cfg().b.c.get_or_else('default') # default value for nested parameter
373386 2
387+
374388 >>> cfg().b.undefined.get_or_else('default')
375389 'default'
376390 """
377391
378392 return _Accessor (self , None )
379393
380- def dispatch (self , callback : Callable = None ):
381- """
382- Return a call holder.
383-
384- Examples:
385- >>> def debug_print(path, index, *arg, **kws):
386- ... return (path, index, arg, kws)
387- >>> ch = param_scope().dispatch(debug_print)
388- >>> ch.my.foo(a=1,b=2)
389- ('my.foo', None, (), {'a': 1, 'b': 2})
390-
391- >>> ch.myspace2.gee(c=1,d=2)
392- ('myspace2.gee', None, (), {'c': 1, 'd': 2})
393- """
394-
395- @dynamic_dispatch
396- def wrapper (* arg , ** kws ):
397- with param_scope () as hp :
398- name = hp ._name
399- index = hp ._index
400- return callback (name , index , * arg , ** kws )
401-
402- return wrapper
403-
404- def callholder (self , callback : Callable = None ):
405- return self .dispatch (callback )
406-
407394 @staticmethod
408395 def loads (s ):
409- """
410- Load parameters from JSON string, similar as `json.loads`.
396+ """Load parameters from JSON string, similar as `json.loads`.
397+
398+ Examples
399+ --------
400+ >>> hp = HyperParameter.loads('{"a": 1, "b": {"c": 2}}')
401+ >>> hp.a
402+ 1
411403 """
412404 obj = json .loads (s )
413405 return HyperParameter (** obj )
414406
415407 @staticmethod
416408 def load (f ):
417- """
418- Load parameters from json file, similar as `json.load`.
419- """
420- obj = json .load (f )
421- return HyperParameter (** obj )
409+ """Load parameters from json file, similar as `json.load`."""
410+ return HyperParameter .load (f .read ())
422411
423412
424413class param_scope (HyperParameter ):
0 commit comments