TL;DR
dict3['key1']
-> returns a list
- i.e.
[{'nest_key': ['this is harder']}]
dict3['key1'][0]
-> returns first item in the list
- i.e.
{'nest_key': ['this is harder']}
dict3['key1'][0]['nest_key']
-> returns the nest_key value in the inner dict
dict3['key1'][0]['nest_key'][0]
-> returns the first item in the inner dict
dict3['key1'][0]['nest_key'][1]
-> returns the 2nd item in the inner dict
dict3['key1'][0]['nest_key'][1][0]
-> returns the 1st string in the 2nd item in the inner dict
dict3['key1'][0]['nest_key'][1][0][0]
-> returns the 1st character of the 1st string in the 2nd item in the inner dict
In Long
Firstly, collections.defaultdict
is a good friend. https://docs.python.org/3/library/collections.html#collections.defaultdict
An example usage:
from collections import defaultdict
x = defaultdict(list)
x['key1'].append('abc')
print(x)
[out]:
defaultdict(<class 'list'>, {'key1': ['abc']})
Next if we kind of initialize the "types" of your dict3
object, it will look something like this:
In human words, dictionary of list of dictionary of list of strings or list of strings, i.e. "messy"/"awkward", see also
In Python types:
from collections import defaultdict
x = defaultdict(lambda: [defaultdict] )
x['key1'].append({'abc': 'foo bar'})
print(x)
[out]:
defaultdict(<function <lambda> at 0x7f75cebca0d0>,
{'key1': [<class 'collections.defaultdict'>, {'abc': 'foo bar'}]})
If we look at first how you can/should initialize dict3
type, you would do something like:
from collections import defaultdict
x = defaultdict(lambda: list(defaultdict(lambda: list)) )
x['key1'].append({'nest_key': ['this is harder']})
print(x)
[out]:
defaultdict(<function <lambda> at 0x7f75cee11940>,
{'key1': [defaultdict(<function <lambda>.<locals>.<lambda> at 0x7f75cf38c4c0>, {}),
{'nest_key': ['this is harder']}]})
And then to access the 'this is harder'
string you would do:
x['key1']
-> returns a list
- i.e.
[{'nest_key': ['this is harder']}]
x['key1'][0]
-> returns first item in the list
- i.e.
{'nest_key': ['this is harder']}
x['key1'][0]['nest_key']
-> returns the nest_key value in the inner dict
x['key1'][0]['nest_key'][0]
-> returns the first item in the inner dict
But what happens if I want dict3 = {'key1':[{'nest_key':['this is harder',['this_entry']]}]}
, where the penultimate inner most list contains a list or string?
To initialize the values, you would have done something like
from collections import defaultdict
x = defaultdict(lambda: list(defaultdict(lambda: list)) )
x['key1'].append({'nest_key': ['this is harder']})
x['key1'][0]['nest_key'].append('this is inserting a string')
x['key1'][0]['nest_key'].append(['this is inserting a list'])
print(type(x['key1'][0]['nest_key'][0])) # "this is harder" -> str
print(type(x['key1'][0]['nest_key'][1])) # "this is inserting a string" -> str
print(type(x['key1'][0]['nest_key'][2])) # ['this is inserting a list'] -> list
[out]:
<class 'str'>
<class 'str'>
<class 'list'>
To summarize the initialization:
Human words |
Initialization |
Usage |
Outputs |
dictionary of list |
x = defaultdict(list) |
x['key1'].append('abc') |
{'key1': ['abc']} |
dictionary of list of dict |
x = defaultdict(lambda: list(defaultdict)) |
x['key1'].append({'key2':'abc'})` |
{'key1': [{'key2':'abc'}]} |
dictionary of list of dict of list |
x = defaultdict(lambda: list(defaultdict(lambda: list)) ) |
x['key1'].append({'key2': ['foo bar']}) |
defaultdict(<function at 0x7f75cebbcc10>, {'key1': [defaultdict(<function .. at 0x7f75cebbc940>, {}), {'key2': ['foo bar']}]}) |
Q: Why do I bother with how the object is initialize if I just to want access an item inside?
A: If you don't know how the object is initialize, you most probably can't modify / remove / add items. And also knowing how it's initialized also helps you understand how to access the items inside.
Food for thought
If access/parsing to the item you want is kinda complicated, is there an easier way to store your data? I.e. is there a better data structure?