0

Expected result:

main_dict = { 
                'a':
                    { 0: 'Letter a',
                      1: 'Letter a',
                      2: 'Letter a',},

                'b':
                    { 0: 'Letter b',
                      1: 'Letter b',
                      2: 'Letter b',},

                'c':
                    { 0: 'Letter c',
                      1: 'Letter c',
                      2: 'Letter c',}

             }

My program, version 1; the expected results is the output.

# my_program.py
def fill_dict(a_dict, a_key):

    if not a_dict.has_key(a_key):
        a_dict[a_key] = {}

    for i in xrange(3):
        a_dict[a_key][i] = 'Letter {}'.format(a_key)

def main():
    main_dict = {}

    a_list = ['a', 'b', 'c']

    for item in a_list:
        fill_dict(main_dict, item)

if __name__ == '__main__':
    main()

Refactored program using defaultdicts; result is main_dict = {}.

# defaultdict_test.py
import collections

def fill_dict(a_dict, a_key):

    a_dict = collections.defaultdict(dict)

    for i in xrange(3):
        a_dict[a_key][i] = 'Letter {}'.format(a_key)

def main():
    main_dict = {}

    a_list = ['a', 'b', 'c']

    for item in a_list:
        fill_dict(main_dict, item)

if __name__ == '__main__':
    main()

Any pointers on what I'm doing wrong? Thanks.

dawg
  • 98,345
  • 23
  • 131
  • 206
baktin
  • 153
  • 1
  • 5

2 Answers2

2

You are passing main_dict into fill_dict, then assigning a new defaultdict to the local variable a_dict. You never pass that value back out.

In your program that works, you don't reassign the local, so when you call methods on a_dict, you are modifying the value passed in, which is the main_dict value from main.

This distinction, between reassigning, and mutating with methods, is subtle but important. This article has more on names, values, and their interactions: Facts and myths about Python names and values.

Ned Batchelder
  • 364,293
  • 75
  • 561
  • 662
0

Pointers:

  1. Use in vs has_key in your first version. The method has_key has been depricated and removed in Python 3
  2. Remove a_dict = collections.defaultdict(dict) from fill_dict
  3. Change main_dict = {} to main_dict = collections.defaultdict(dict) in main

Done!

import collections

def fill_dict(a_dict, a_key):
    for i in xrange(3):
        a_dict[a_key][i] = 'Letter {}'.format(a_key)        

def main():
    main_dict = collections.defaultdict(dict)

    a_list = ['a', 'b', 'c']

    for item in a_list:
        fill_dict(main_dict, item)

Final pointer: Get to know list, set and dict comprehensions. You can do this data structure in a single line:

>>> {c:{i: 'Letter {}'.format(c) for i in range(3)} for c in 'abc'}
{'a': {0: 'Letter a', 1: 'Letter a', 2: 'Letter a'}, 'c': {0: 'Letter c', 1: 'Letter c', 2: 'Letter c'}, 'b': {0: 'Letter b', 1: 'Letter b', 2: 'Letter b'}}

If you look at it -- it is almost a version of what you have as your desired result if you format it that way:

dict_you_want={
                   c:
                       {  i: 'Letter {}'.format(c) 
                            for i in range(3)  }   # , 

                      for c in 'abc'
              }

which will execute just as I have it there...

Community
  • 1
  • 1
dawg
  • 98,345
  • 23
  • 131
  • 206