1

I come across this issue on a regular basis, hopefully someone has an elegant solution...

x = {'a':1, 'b':{'c':2}}

now:

x.get('a', None) = 1

x.get('b', None).get('c', None) = 2

what about:

x.get('a', None).get('c', None) = 


---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-5-278862f593e8> in <module>()
----> 1 x.get('a', None).get('c')

AttributeError: 'int' object has no attribute 'get'

#

Is there a simple pythonic one-liner for handling cases like this? (without using a bunch of if statements)

Thanks!

#

Thanks for all the comments/feedback. I'm looking for an elegant one-liner, as I come across this on a regular basis. Obviously this is a toy-example, which was constructed just to explain the problem. I would prefer not to use try/catch blocks or wrap the code in long if statements. Thanks!

vgoklani
  • 8,218
  • 11
  • 52
  • 81
  • 5
    You quite often try to assign to a key using `get` and default values of `None`? Really??? What are you trying to do exactly? – Jon Clements Dec 02 '13 at 15:38
  • 2
    Your request, `x.get('a', None).get('c', None)` is not going to work, because 'a' doesn't have 'c' nested underneath it. – ericmjl Dec 02 '13 at 15:40
  • 1
    ``.get``, as the name implies, can't be used to assign values to a dict key. ``d.get(1, None)`` is a syntax error. In addition, the ``None`` is redundant in the first place, because the ``get`` method already returns ``None`` if the requested key isn't in the dict (the second argument is optional, and is used to override that behavior). – Max Noel Dec 02 '13 at 15:43
  • I see you're trying to build a 'tree' of data, not simply nested dicts. Is it correct? – Don Dec 02 '13 at 15:49
  • The data is inherently unstructured, which means that not each node has the same number of branches. – vgoklani Dec 02 '13 at 16:12

4 Answers4

2

The usual syntax to access nested dictionary keys is:

>>> x = {'a':1, 'b':{'c':2}}
>>> x['b']['c']
2
>>> x['b']['c'] = 100
>>> x['b']['c']
100

This will throw a key error on missing keys:

>>> x['b']['d']
...
KeyError: 'd'

Which you could wrap in a try-catch:

>>> try:
...     x['b']['d']
... except KeyError as err:
...     # do something when no key is present ...
...     pass

If you are looking for a "catch-all non-existing keys and always do the right thing" kind of solution, I guess you'll have to write some thin wrapper around your specific data structure.

miku
  • 161,705
  • 45
  • 286
  • 300
1

Here's a generator that will grab the nested value if it's nested, and just the value if it isn't nested:

x = {'a':1, 'b':{'c':2}}
def get_value(x, nested_key='c'):
    for k, v in x.items():
        if isinstance(v, dict):
            yield v[nested_key]
        else:
            yield v

Here's a demo:

>>> for value in get_value(x):
        print (value)


2
1
aIKid
  • 21,361
  • 4
  • 36
  • 58
  • ok, so we can get endpoints like this. what about the nodes? might not be in scope for the answer, [but as you know I like creating these kinds of data structures...](http://stackoverflow.com/questions/635483/what-is-the-best-way-to-implement-nested-dictionaries-in-python/19829714#19829714) – Aaron Hall Dec 02 '13 at 16:03
1

There isn't a Pythonic one liner. Arbitrary nesting requires some arbitrary code. The Pythonic way is to ask for forgiveness meaning a try-catch block.

Think this through and it makes sense. Imagine debugging your nested get call above if it worked. Which layer was missing the key?

Sean Perry
  • 3,588
  • 1
  • 14
  • 29
  • I agree, but I wouldn't call it arbitrary nesting, as it entails having to work with highly unstructured data. The point of the post was to see if someone had a clever solution. – vgoklani Dec 03 '13 at 20:57
0

Do you mean such construction:

try:
    x['a']['b'] = 1  # getting or setting values for existing dicts/keys
except:
    pass  # or do something in case dict does not exists
akaRem
  • 6,200
  • 3
  • 25
  • 40