2

I have a function that takes in a list and outputs a dictionary. I am creating a dictionary inside the loop and assigning the dictionary values inside the function. A simplified version of what I want to ask is below:

import numpy as np

def get_myDict(tmp_list):
    my_dict = dict.fromkeys(tmp_list, 
                            dict.fromkeys([i**2 for i in tmp_list],0))
    for i in tmp_list:
        my_list = [j for j in np.arange(i)]
        my_dict[i][i**2] = sum(my_list[:]) + i
    return my_dict 

Output from this looks like:

[In 1]: get_myDict([1,2,3,4])
[Out 1]: {1: {1: 1, 4: 3, 9: 6, 16: 10},
          2: {1: 1, 4: 3, 9: 6, 16: 10},
          3: {1: 1, 4: 3, 9: 6, 16: 10},
          4: {1: 1, 4: 3, 9: 6, 16: 10}}

Whereas I would expect the output to be

{1: {1: 1, 4: 0, 9: 0, 16: 0},
 2: {1: 0, 4: 3, 9: 0, 16: 0},
 3: {1: 0, 4: 0, 9: 6, 16: 0},
 4: {1: 0, 4: 0, 9: 0, 16: 10}}

I get the desired output if I define the my_dict inside the function with the following:

my_dict = {1: {16: 0, 1: 0, 4: 0, 9: 0}, 
           2: {16: 0, 1: 0, 4: 0, 9: 0}, 
           3: {16: 0, 1: 0, 4: 0, 9: 0}, 
           4: {16: 0, 1: 0, 4: 0, 9: 0}}

I believe that this has to do with shared references in some way. Can someone explain what am I doing wrong here?

Vakratund
  • 169
  • 1
  • 2
  • 10

2 Answers2

3

You are right, you are actually creating a single dictionary with quadratic keys and reference it multiple times.

Use a dict comprehension (since Python 2.7):

my_dict = {k: {k2: 0 for k2 in [i**2 for i in tmp_list]} for k in tmp_list}

Michael Butscher
  • 10,028
  • 4
  • 24
  • 25
1

The reason is that you're effectively passing a single value to the dict.fromkeys() method. To illustrate what you're doing:

import numpy as np

def get_myDict(tmp_list):
    value = dict.fromkeys([i**2 for i in tmp_list], 0)
    my_dict = dict.fromkeys(tmp_list, value)
    ...

So all of the dictionaries will reference the same value dictionary.

Perhaps a collection.defaultdict would be more convenient here?

Wolph
  • 78,177
  • 11
  • 137
  • 148