5 ms·
There are quite a few nay-votes here, so I'll give a yay vote. In the past I have had to deal with very complex configuration systems; several thousands of lin
by cjhanks 9y ago
There are quite a few nay-votes here, so I'll give a yay vote.
In the past I have had to deal with very complex configuration systems; several thousands of lines of XML which were supposed to direct many applications.
And writing:
value['this']['that']['the_other']
vs
value.this.that.the_other
Really starts to matter for code legibility. Of course if you change your XML configs your Python will break - but it would likely break in any case.
The other case where I have found this applicable is when I have complicated JSON structures in the form of user input. Typically I augment this style by using a JSONSchema that ensures attributes do exist and have defaults (or None).
- lobster_johnson 9y agoOne option would be: value['this.that.the_other'] Bonus: Make it support JSONPath and you can use it to extract lots of things at arbitrarily nested levels.
- smoe 9y agoI see the value in the latter for code legibility. My gripe with it is, when I'm new to a project that uses a dict implementation like that: how do I know what happens if for example `that` is missing? Does it raise AttributeError, KeyError or just return None? Personally I'd prefer a helper functions like deep_get(dict_, dotted_path[, default]) -> value You stil have to check the docs/source what exactly happens, but it is just one simple function instead of magic methods. And i can keep using plain dicts everywhere. EDIT: To clarify a bit. An experienced Python developer should immediately recognize a call like `deep_get(value,'this.that.the_other')` as something project/framework specific and not built-in, while `value.this.that.the_other` is ambiguous.
- CloudYeller 9y agoYou can get part of the way there with operator.attrgetter: NT = collections.namedtuple('NT', ['x', 'y']) nt1 = NT(1, 2) nt2 = NT(nt1, 'asdf') assert nt2.x.y == 2 get_two = operator.attrgetter('x.y') assert get_two(nt2) == 2 If you wrap the operator.attrgetter in a try/catch, you can force a default too: https://pastebin.com/bFxGr22E https://pastebin.com/bFxGr22E
- smoe 9y agoI never thought much about best implementation because I only used it i think once in ten years. But afaik I used something like this, that does the job and is easy to read _empty = object() def deep_get(dct, dotted_path, default=_empty): for key in dotted_path.split('.'): try: dct = dct[key] except KeyError: if default is _empty: raise return default return dct
- cjhanks 9y agoPersonally I try to implement it as an AttributeError, it seems the most intuitive. By the way, I do understand your point and it's pretty valid in a lot of cases.
- nerdponx 9y agoYou can use `get` from the `toolz` package: toolz.get(value, ['this', 'that', 'the_other'] There's also a Cython implementation called `cytoolz`.
- Varriount 9y agoWhat do you typically use for enforcing a schema? I've been using Good[0], however since it is meant for general data structures, users don't get line/column printouts for invalid data. [0] https://pypi.python.org/pypi/good/0.0.7-0 https://pypi.python.org/pypi/good/0.0.7-0
- cjhanks 9y agoI like jsonschema [1][2], primarily because it's a cross-language standard. Though, I have never used `Good` - it seems to be pretty nice if you're Python focused. [1] https://pypi.python.org/pypi/jsonschema https://pypi.python.org/pypi/jsonschema [2] http://json-schema.org/ http://json-schema.org/
- msellout 9y agoGive `destructure` a try https://github.com/selik/destructure https://github.com/selik/destructure
- xapata 9y agoBetter would be to code depth-first-search and breadth-first-search functions and use those on plain nested dictionaries. That's what XML did via XPATH.