1

May I ask: is the try block 2nd option considered poor practice? And if so, is there a more succinct way of testing a nested dict before referencing a sub key that may or may not exist?

Coming to python from perl...

Thank you :)

b = None
# a['x'] = {}
# a['x']['y'] = Wibble
if 'x' in a and 'y' in a['x']:
  b = a['x']['y']
if b is not None:
  # Do stuff with b

vs

b = None
try:
  b = a['x']['y']
except:
  pass
if b is not None:
  # Do stuff with b
OneCricketeer
  • 179,855
  • 19
  • 132
  • 245
Tim Watts
  • 13
  • 4
  • Does this answer your question? [Elegant way to check if a nested key exists in a dict?](https://stackoverflow.com/questions/43491287/elegant-way-to-check-if-a-nested-key-exists-in-a-dict) – fynmnx Aug 04 '22 at 14:22
  • I generally use this way if not very deeply nested https://stackoverflow.com/a/61158507/2308683 – OneCricketeer Aug 04 '22 at 14:24
  • Thanks @fynmnx - I see that try-except is considered "good" there. I'll go with that because it's brief and clean. Useful to see that they only catch the specific exception KeyError Many thanks for that. – Tim Watts Aug 04 '22 at 14:28

3 Answers3

1

try this

> b=a.get("x",{}).get("y")
  if b:
    #Do stuff with b
Mouad Slimane
  • 913
  • 3
  • 12
  • A very interesting technique - thank you for that :) – Tim Watts Aug 04 '22 at 14:30
  • the `.get()` method is a safe way to attempt to grab a key value and return a default if it's not there. The first `get()` checks for key 'x' and returns an empty dict if it's not there. This ensures the next `get()` will be called on a dict. The second `get` will return either the value under 'y' or `None` (the default if a default return is not specified) – Joe Carboni Aug 04 '22 at 14:35
0

I'd go for the new walrus operator in 3.8:

a = { 'b': { 'c': 1, 'd': 2 }, 'e': {} }

if (b := a.get('b')) and (c := b.get('c')):
   print(c)

so if b is not present a.get('b') will return None and the and condition would return False.

John M.
  • 775
  • 4
  • 16
0

Yes its even recommended as a common coding style: It is easier to ask for forgiveness than permission.

The only thing I would change is to not catch all exceptions, but just KeyError. And also I would use the else case to do the processing, instead of the None test.

try:
  b = a['x']['y']
except KeyError:
  pass
else:
  # do stuff with b
Chris
  • 2,461
  • 1
  • 23
  • 29