A base.
I looked around and found this article that gave me a base I could riff off. I want the attributes accessed to appear in the dictionary. I want nested attribut access to "work".A new implementation.
I came up with the following code. any attributes starting with an underscore are excused from jiggery-pokery as Spyder/Ipython sets a few.class AttrInDict(dict): "Move none-hidden attribute access to dict item" def __init__(self, *args, **kwargs): self._extra_attr = set() super().__init__(*args, **kwargs) def __getattr__(self, item): if item[0] != '_': if (not super().__contains__(item) # Its new or (item in self._extra_attr # It's an attr, now None and super().__getitem__(item) is None)): super().__setitem__(item, AttrInDict()) return super().__getitem__(item) else: return super().__getattr__(item) def __setattr__(self, item, val): if item[0] != '_': super().__setitem__(item, val) self._extra_attr.add(item) else: super().__setattr__(item, val) def __dir__(self): "To get tooltips working" supr = set(super().__dir__()) return list(supr | self._extra_attr)
Class in action.
Python 3.7.1 | packaged by conda-forge | (default, Mar 13 2019, 13:32:59) [MSC v.1900 64 bit (AMD64)]
Type "copyright", "credits" or "license" for more information.
IPython 7.1.1 -- An enhanced Interactive Python.
Restarting kernel...
In [1]: runfile('dictindict.py', wdir='pp_reg')
In [2]: # Start like a dict
In [3]: d = AttrInDict(x=3)
In [4]: d
Out[4]: {'x': 3}
In [5]: # Access like an attribute
In [6]: d.x
Out[6]: 3
In [7]: # Access an unknown attribute creates a sub-"dict"
In [8]: d.foo
Out[8]: {}
In [9]: d
Out[9]: {'x': 3, 'foo': {}}
In [10]: d.foo = 123
In [11]: d.foo
Out[11]: 123
In [12]: d
Out[12]: {'x': 3, 'foo': 123}
In [13]: # Access an unknown, unknown attribute creates sub, sub "dicts"
In [14]: d.tick.tock
Out[14]: {}
In [15]: d
Out[15]: {'x': 3, 'foo': 123, 'tick': {'tock': {}}}
In [16]: # Dict hierarchy preserved
In [17]: d.tick.tack = 22
In [18]: d
Out[18]: {'x': 3, 'foo': 123, 'tick': {'tock': {}, 'tack': 22}}
In [19]: d.tick.teck = 33
In [20]: d
Out[20]: {'x': 3, 'foo': 123, 'tick': {'tock': {}, 'tack': 22, 'teck': 33}}
In [21]: d.tick.tock.tuck = 'Boo'
In [22]: d
Out[22]: {'x': 3, 'foo': 123, 'tick': {'tock': {'tuck': 'Boo'}, 'tack': 22, 'teck': 33}}
In [23]: # Can tack on hierarchy to previous attribute with None value
In [24]: d.foo = None
In [25]: d
Out[25]:
{'x': 3,
'foo': None,
'tick': {'tock': {'tuck': 'Boo'}, 'tack': 22, 'teck': 33}}
In [26]: d.foo.bar = 42
In [27]: d
Out[27]:
{'x': 3,
'foo': {'bar': 42},
'tick': {'tock': {'tuck': 'Boo'}, 'tack': 22, 'teck': 33}}
In [28]: # Still like a dict
In [29]: d.keys()
Out[29]: dict_keys(['x', 'foo', 'tick'])
In [30]: d.values()
Out[30]: dict_values([3, {'bar': 42}, {'tock': {'tuck': 'Boo'}, 'tack': 22, 'teck': 33}])
In [31]: