I propose to add a get_deep(*args, default=_sentinel) method to dict.
It can accept a single argument, that must be an iterable, or multiple arguments.
The first element must be a key of the dict. If there's not a second element, the value is returned. If it's present, it tries to use it as an argument for the eventual __getitem__() of the value object, and so on.
In this process, if a KeyError, an IndexError or a TypeError is raised, if default is set its value is returned, otherwise the exception will be raised.
Example:
d = {1: [42]} d.get_deep(1, 0) # 42 d.get_deep(range(3), default=1981) # 1981 d.get_deep((1, 1)) # IndexError: list index out of range
seems a bit like https://www.python.org/dev/peps/pep-0505/
eg `d?[1]?[0]`
On Sun, 23 May 2021 at 15:30, Thomas Grainger tagrain@gmail.com wrote:
seems a bit like https://www.python.org/dev/peps/pep-0505/
eg `d?[1]?[0]`
No, I do not want to suppress the exception, only to have a way to access a nested object in a complicate dict, for example a dict generated by a JSON.
In your example,
d = {1: [42]} d.get_deep(2, 0) # KeyError: 2 d = None d.get_deep(1, 0) # AttributeError: 'NoneType' object has no attribute 'get_deep'
Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/ZKYLSY... Code of Conduct: http://python.org/psf/codeofconduct/
On 2021-05-23 13:37, Marco Sulla wrote:
I propose to add a get_deep(*args, default=_sentinel) method to dict.
It can accept a single argument, that must be an iterable, or multiple arguments.
The first element must be a key of the dict. If there's not a second element, the value is returned. If it's present, it tries to use it as an argument for the eventual __getitem__() of the value object, and so on.
In this process, if a KeyError, an IndexError or a TypeError is raised, if default is set its value is returned, otherwise the exception will be raised.
Example:
d = {1: [42]} d.get_deep(1, 0) # 42 d.get_deep(range(3), default=1981) # 1981 d.get_deep((1, 1)) # IndexError: list index out of range
A slight problem here: a tuple (1, 1) can be a key of the dict.
Also, if the first lookup returns a list or a tuple, and an argument can be an index of that list, would be make sense to add a similar method to lists and tuples?
On Mon, May 24, 2021 at 1:24 AM MRAB python@mrabarnett.plus.com wrote:
Also, if the first lookup returns a list or a tuple, and an argument can be an index of that list, would be make sense to add a similar method to lists and tuples?
Or, better: make it a stand-alone function, not a method of anything. Although that kinda takes it out of python-ideas territory because it could easily be a personal library function instead:
_sentinel = object() # or see other proposals def get_deep(obj, *keys, default=_sentinel): if len(keys) == 1: keys = list(keys[0]) try: for key in keys: obj = obj[key] except (LookupError, TypeError): # the OP did include TypeError if default is not _sentinel: return default raise return obj
Done. Personally, I'd just go with "except LookupError:", but this is another advantage of personal library functions: you don't have to bikeshed them with everyone else :)
ChrisA
The pytoolz/cytoolz project already has this: https://toolz.readthedocs.io/en/latest/api.html#toolz.dicttoolz.get_in
On Sun, May 23, 2021, 11:44 Chris Angelico rosuav@gmail.com wrote:
On Mon, May 24, 2021 at 1:24 AM MRAB python@mrabarnett.plus.com wrote:
Also, if the first lookup returns a list or a tuple, and an argument can be an index of that list, would be make sense to add a similar method to lists and tuples?
Or, better: make it a stand-alone function, not a method of anything. Although that kinda takes it out of python-ideas territory because it could easily be a personal library function instead:
_sentinel = object() # or see other proposals def get_deep(obj, *keys, default=_sentinel): if len(keys) == 1: keys = list(keys[0]) try: for key in keys: obj = obj[key] except (LookupError, TypeError): # the OP did include TypeError if default is not _sentinel: return default raise return obj
Done. Personally, I'd just go with "except LookupError:", but this is another advantage of personal library functions: you don't have to bikeshed them with everyone else :)
ChrisA _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/YM6KCR... Code of Conduct: http://python.org/psf/codeofconduct/
On Sun, 23 May 2021 at 19:41, Todd toddrjen@gmail.com wrote:
The pytoolz/cytoolz project already has this: https://toolz.readthedocs.io/en/latest/api.html#toolz.dicttoolz.get_in
It seems a project that is used by many people. I think that JSON is so much used that that function could be added to the builtin dict.
On Sun, May 23, 2021, 11:44 Chris Angelico rosuav@gmail.com wrote:
On Mon, May 24, 2021 at 1:24 AM MRAB python@mrabarnett.plus.com wrote:
Also, if the first lookup returns a list or a tuple, and an argument can be an index of that list, would be make sense to add a similar method to lists and tuples?
Or, better: make it a stand-alone function, not a method of anything. Although that kinda takes it out of python-ideas territory because it could easily be a personal library function instead:
_sentinel = object() # or see other proposals def get_deep(obj, *keys, default=_sentinel): if len(keys) == 1: keys = list(keys[0]) try: for key in keys: obj = obj[key] except (LookupError, TypeError): # the OP did include TypeError if default is not _sentinel: return default raise return obj
Done. Personally, I'd just go with "except LookupError:", but this is another advantage of personal library functions: you don't have to bikeshed them with everyone else :)
ChrisA _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/YM6KCR... Code of Conduct: http://python.org/psf/codeofconduct/
Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/MEQM2S... Code of Conduct: http://python.org/psf/codeofconduct/
On Sun, 23 May 2021 at 17:22, MRAB python@mrabarnett.plus.com wrote:
On 2021-05-23 13:37, Marco Sulla wrote:
I propose to add a get_deep(*args, default=_sentinel) method to dict.
It can accept a single argument, that must be an iterable, or multiple arguments.
The first element must be a key of the dict. If there's not a second element, the value is returned. If it's present, it tries to use it as an argument for the eventual __getitem__() of the value object, and so on.
In this process, if a KeyError, an IndexError or a TypeError is raised, if default is set its value is returned, otherwise the exception will be raised.
Example:
d = {1: [42]} d.get_deep(1, 0) # 42 d.get_deep(range(3), default=1981) # 1981 d.get_deep((1, 1)) # IndexError: list index out of range
A slight problem here: a tuple (1, 1) can be a key of the dict.
This problem can raise only if you want to get the first level, but for this purpose there's __getitem__ already.
You can have:
d = {(1, 1): [5, 7]}
and probably you will write
d.get_deep((1, 1), 1)
or
d.get_deep([(1, 1), 1])
Also, if the first lookup returns a list or a tuple, and an argument can be an index of that list, would be make sense to add a similar method to lists and tuples? _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/XQAFJE... Code of Conduct: http://python.org/psf/codeofconduct/