Looping through and Accessing nested dictionary elements

Question:

I am trying to append dictionary elements to a list:

test1 = pd.DataFrame
list_of_origins = []
list_of_destinations = []
for test in list_of_details_per_flight:
    
    if test['airport']['origin'] is not None:
        print(test['airport']['origin']['position'])

However I get the following error for the fourth line:

TypeError: byte indices must be integers or slices, not str

When I check for the type per iteration it states it is a dictionary object, which hence should be accessible by their keys, so I think I am doing it right.

Asked By: jacktheripper

||

Answers:

print(type(test['airport'])) is a class dict if print(type(test['airport']['origin'])) is not a class NoneType

That’s a given, since you’d need test['airport'] to be a dictionary to be able to access ['origin'] at all – in fact, test['airport'] not being a dictionary is possibly what’s causing the error.

Have you tried printing type(test['airport']) before the if block? Is it always a dictionary? If it was, then if test['airport']['origin'] should not be raising that error, unless test was ever not a dictionary, but you’ve confirmed that it is:

type(test) is always a class dict.


print(type(test['airport']['origin'])) is a class NoneType and class dict

If that was always so, then that error would never be raised on the test['airport']['origin']['position']. (And these two lines are the only possible sources of this error in your snippet.)



I can’t test any of these without the list_of_details_per_flight you used, but I can suggest 3 possible ways to go about this without raising error:

Suggestion 1: add more conditions

You can individually check if that each of the 3 keys can be accessed and only print if they all can, using for...else.

for test in list_of_details_per_flight:
    for k in ['airport', 'origin', 'position']:
        if not isinstance(test, dict):
            # print(f"can't access ['{k}'] of {type(test)} {test}")
            break

        if k not in test:
            # print(f"no value for ['{k}'] in {test}")
            break
        test = test[k] ## OR JUST
        # test = test.get(k) ## [ if you want to omit the if k not in test block ]
    else: print(test) ## else in for-else executes if the for block doesn't break

Suggestion 2: just print from inside a try block

for test in list_of_details_per_flight:
    try: print(test['airport']['origin']['position'])
    except: pass ## OR 
    # except Exception as e: print(type(e), e) # print an error msg for that test

Suggestion 3: print all position values

I have a set of functions which can be used to retrieve all values in list_of_destinations that are paired with position as a key.

allPos = getNestedVal(
    list_of_destinations, nKey='position', rForm='_all', 
    pKeys=[], objName='list_of_destinations'
)

for pos in allPos: print(pos['val'], '<---', pos['expr']) 
  • If you want only position values that are inside an origin inside an airport, pass pKeys=['airport', 'origin'] to getNestedVal (to specify parent keys).
  • pos['expr'] will contain the full keys-path like list_of_destinations[0]['airport']['origin']['position'] etc., but if you only want all the values, you can get them in a flat list by setting rForm='just_vals_all'.

You can also combine the last two suggestions by printing all position values in test in the except block.

for test in list_of_details_per_flight:
    try: print(test['airport']['origin']['position'])
    except Exception as e: : pass ## OR 
        # print(type(e), e) # print an error msg for that test
        tPos = getNestedVal(test, nKey='position', rForm='_all', pKeys=[], objName='test')
        # if not tPos:  print('tThis test contains no position values')
        for pos in tPos: print('t', pos['val'], '<---', pos['expr']) 
  • If you want only the first position value instead of a list of all of them, remove _all from the end of rForm.

Note: getNestedVal can get rather slow if list_of_details_per_flight is large; it’s mostly meant for a one-time used to find the list of keys in the path to certain values in deeply nested dictionaries, and then to use the paths from then on.

Answered By: Driftr95
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.