0

I wish to construct a Python dict from the keys of another dict and build new lists to use as the dict values. I have written two pieces of code which I thought would be equivalent but are not.

The first piece of code I prefer since it doesn't use a new list object within the loop and an extra assignment line at the end as seen in the second piece of code. I was hoping using dict.fromkeys() would negate the need for these and make the code neater/more readable.

Code 1:

class_list = ['a','b','c','d']
X_classes = {'foo':['a','b'],'bar':['c','d']}
X_indices = dict.fromkeys(X_classes,[]) # i.e., {'foo':[],'bar':[]}
for xc in X_classes.items():
    for c in xc[1]:
        X_indices[xc[0]].append(class_list.index(c))

Code 2:

class_list = ['a','b','c','d']
X_classes = {'foo':['a','b'],'bar':['c','d']}
X_indices = {}
for xc in X_classes.items():
    indices = []
    for c in xc[1]:
        indices.append(class_list.index(c))
    X_indices[xc[0]] = indices

Code 1 produces the unexpected result: X_indices = {'foo':[0,1,2,3],'bar':[0,1,2,3]}. This led me to write Code 2, which produces the expected result: X_indices = {'foo':[0,1],'bar':[2,3]}

I would be grateful if someone could explain to me why these two pieces of code generate different results.

Dave
  • 312
  • 3
  • 11

1 Answers1

2

Because dict.fromkeys uses the object you give it as the value: that is, the same object each time. So each value in the dictionary is a reference to the same list.

fromkeys is only really useful with immutable values, eg strings or ints.

However, a much neater implementation would be to use a list comprehension. Also note, you can use tuple unpacking in the iteration through the items.

for k, v in X_classes.items():
     X_indices[k] = [class_list.index(c) for c in v]
Daniel Roseman
  • 588,541
  • 66
  • 880
  • 895
  • Very clear explanation - I can see now `fromkeys` is not applicable in this case. Also, I really like the use of tuple unpacking and list comprehension to neaten up the code. – Dave Aug 13 '19 at 09:56