I'm interrogating a nested dictionary using the dict.get('keyword') method. Currently my syntax is...
M = cursor_object_results_of_db_query for m in M: X = m.get("gparents").get("parent").get("child") for x in X: y = x.get("key")
However, sometimes one of the "parent" or "child" tags doesn't exist, and my script fails. I know using get()
I can include a default in the case the key doesn't exist of the form...
get("parent", '') or get("parent", 'orphan')
But if I include any Null
, ''
, or empty I can think of, the chained .get("child")
fails when called on ''.get("child")
since ""
has no method .get()
.
The way I'm solving this now is by using a bunch of sequential try-except
around each .get("")
call, but that seems foolish and unpython---is there a way to default return "skip"
or "pass"
or something that would still support chaining and fail intelligently, rather than deep-dive into keys that don't exist?
Ideally, I'd like this to be a list comprehension of the form:
[m.get("gparents").get("parent").get("child") for m in M]
but this is currently impossible when an absent parent causes the .get("child")
call to terminate my program.
Access Values using get() Another way to access value(s) in a nested dictionary ( employees ) is to use the dict. get() method. This method returns the value for a specified key. If the specified key does not exist, the get() method returns None (preventing a KeyError ).
just write d. items() , it will work, by default on iterating the name of dict returns only the keys.
get()—method comes in: it returns the value for a specified key in a dictionary. This method will only return a value if the specified key is present in the dictionary, otherwise it will return None.
Addition of elements to a nested Dictionary can be done in multiple ways. One way to add a dictionary in the Nested dictionary is to add values one be one, Nested_dict[dict][key] = 'value'. Another way is to add the whole dictionary in one go, Nested_dict[dict] = { 'key': 'value'}.
Since these are all python dict
s and you are calling the dict.get()
method on them, you can use an empty dict
to chain:
[m.get("gparents", {}).get("parent", {}).get("child") for m in M]
By leaving off the default for the last .get()
you fall back to None
. Now, if any of the intermediary keys is not found, the rest of the chain will use empty dictionaries to look things up, terminating in .get('child')
returning None
.
Another approach is to recognize that if the key isn't found, dict.get
returns None
. However, None
doesn't have an attribute .get
, so it will throw an AttributeError
:
for m in M: try: X = m.get("gparents").get("parent").get("child") except AttributeError: continue for x in X: y = x.get("key") #do something with `y` probably???
Just like Martijn's answer, this doesn't guarantee that X
is iterable (non-None
). Although, you could fix that by making the last get
in the chain default to returning an empty list:
try: X = m.get("gparents").get("parent").get("child",[]) except AttributeError: continue
Finally, I think that probably the best solution to this problem is to use reduce
:
try: X = reduce(dict.__getitem__,["gparents","parent","child"],m) except (KeyError,TypeError): pass else: for x in X: #do something with x
The advantage here is that you know if any of the get
s failed based on the type of exception that was raised. It's possible that a get
returns the wrong type, then you get a TypeError
. If the dictionary doesn't have the key however, it raises a KeyError
. You can handle those separately or together. Whatever works best for your use case.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With