I'm writing a function to turn a list of dictionaries to a dict of dictionaries. I've since found Find the index of a dict within a list, by matching the dict's value has a better solution because it deals with potential duplicate values by adding an index item rather than pulling from the dicts.
However, in testing I found that the function alters the original list even though I'm making an explicit copy. This is obvious if I attempt to re-run the fuction, but I cannot see why.
def lod2dict(iterable,target="name"):
'''Turn a list of dictionaries into a dict of dicts.
If a dict does not have the target key, that element is skipped.'''
d = {}
copy = list(iterable)
# N.B. It makes no difference whether I use this or
#copy = list[:]
# or
#copy = [x for x in iterable]
for item in copy:
try:
newkey=item[target]
item.pop(target)
d[newkey] = item
except KeyError:
print("Failure for", item)
pass
return d
Here's a run showing the destructive effect with a small dict.
testcase = {"heroes": [
{"name": "Batman", "home": "Wayne Manor", "weapon": "Batarang (TM)"},
{"name": "Spider-Man", "home": "Queens", "weapon": "Sarcasm"},
{"name": "Deadpool", "home": "Good Question. Next?", "weapon": "Sarcasm and swords"},
{"name": "Wonder Woman", "home": "Themyscira", "weapon": "Lasso and sword"},
{"name": "Aquaman", "home": "The Oceans", "weapon": "trident"}
]}
In [4]: lod2dict(testcase['heroes'], 'name')
Out[4]:
{'Aquaman': {'home': 'The Oceans', 'weapon': 'trident'},
'Batman': {'home': 'Wayne Manor', 'weapon': 'Batarang (TM)'},
'Deadpool': {'home': 'Good Question. Next?', 'weapon': 'Sarcasm and swords'},
'Spider-Man': {'home': 'Queens', 'weapon': 'Sarcasm'},
'Wonder Woman': {'home': 'Themyscira', 'weapon': 'Lasso and sword'}}
In [5]: lod2dict(testcase['heroes'], 'name')
Failure for {'home': 'Wayne Manor', 'weapon': 'Batarang (TM)'}
Failure for {'home': 'Queens', 'weapon': 'Sarcasm'}
Failure for {'home': 'Good Question. Next?', 'weapon': 'Sarcasm and swords'}
Failure for {'home': 'Themyscira', 'weapon': 'Lasso and sword'}
Failure for {'home': 'The Oceans', 'weapon': 'trident'}
Out[5]: {}