Python dict using dot notation and chaining
dictionary, python, syntax
Solution
You may need to overwrite getattribute for those edge cases and then use the
object.__getattribute__
Have a look at the module dis. But what you wrote is nicer than disassembling.
>>> import dis
>>> def g():
a.b.c = 4
>>> dis.dis(g)
2 0 LOAD_CONST 1 (4)
3 LOAD_GLOBAL 0 (a)
6 LOAD_ATTR 1 (b)
9 STORE_ATTR 2 (c)
12 LOAD_CONST 0 (None)
15 RETURN_VALUE
Problem
Ideally what I am aiming to accomplish is a class that extends (or is very similar to) a `dict` in Python with the additional capabilities: - Dot-Notation capable for setting and getting values - Key-Value capabilities like `dict` (i.e. setitem,getitem) - Can chain dot-notated operations The goal is if I have something like `example = DotDict()` I could do the following against it `example.configuration.first= 'first'` and it would instantiate the appropriate DotDict instances under `example` with the really painful caveat being that if the operation is not assignment it should simply raise a `KeyError` like a `dict` would do Here is what I have naively assembled ``` class DotDict(dict): def __getattr__(self, key): """ Make attempts to lookup by nonexistent attributes also attempt key lookups. """ import traceback import re s= ''.join(traceback.format_stack(sys._getframe(1),1)) if re.match(r' File.*\n.*[a-zA-Z]+\w*\.[a-zA-Z]+[a-zA-Z0-9_. ]*\s*=\s*[a-zA-Z0-9_.\'"]+',s): self[key] = DotDict() return self[key] return self[key] def __setattr__(self, key, value): if isinstance(value,dict): self[key] = DotDict(value) self[key] = value ``` It works except for some common edge cases, I must say that I absolutely hate this method and there must be a better way. Looking at the stack and running a regular expression on the last line is not a good way to accomplish this. The heart of the matter is that Python interprets lines of code left to right so when it arrives at a statement like `a.b.c = 3` it's first operation is a `getattr(a,b)` and not a `setattr` so I can't determine easily if the last operation in the stack of operations is an assignment. What I would like to know is if there is a good way to determine the last operation in the stack of operations or at least if it's a `setattr`. Edit: This is the solution that I came up with thanks to user1320237's recommendation. ``` class DotDict(dict): def __getattr__(self, key): """ Make attempts to lookup by nonexistent attributes also attempt key lookups. """ if self.has_key(key): return self[key] import sys import dis frame = sys._getframe(1) if '\x00%c' % dis.opmap['STORE_ATTR'] in frame.f_code.co_code: self[key] = DotDict() return self[key] raise AttributeError('Problem here') def __setattr__(self, key, value): if isinstance(value,dict): self[key] = DotDict(value) self[key] = value ``` There's a little bit more in the actual implementation but it does an awesome job. The way it works is that it inspects the last frame in the stack and checks the byte code for a STORE_ATTR operation which means that the operation being performed is of the `a.b.this.doesnt.exist.yet = 'something'` persuasion. I would be curious if this could be done on other interpreters outside of CPython.