2

I tried to create the perfect dictionary for my needs (dict that's containing a dict with values and a list). However it seems that I assigned the same reference over and over.

brands = ['val1', 'val2', 'val3']
infoBrands = dict.fromkeys(brands,
                dict(dict.fromkeys(['nbOffers', 'nbBestOffers'], 0),
                     **dict.fromkeys(['higherPrice'], [])))

infoBrands['val1']['nbOffers'] += 1
print infoBrands

Here the results:

{'val3':
     {'higherPrice': [],
       'nbOffers': 1,
       'nbBestOffers': 0},
  'val2':
       {'higherPrice': [],
        'nbOffers': 1,
        'nbBestOffers': 0},
  'val1':
       {'higherPrice': [],
        'nbOffers': 1,
        'nbBestOffers': 0}
}

As you can see, val1, val2 and val3 refer to the same dict. I'm not sure how I should handle it? Any tips?

martineau
  • 119,623
  • 25
  • 170
  • 301
John Smith
  • 808
  • 3
  • 9
  • 20
  • 2
    `dict.fromkeys` uses the same value for every key, hence the reference issue. Have you looked into `collections.defaultdict` at all? (See e.g. http://bugs.python.org/issue6730) – jonrsharpe Nov 05 '14 at 14:12
  • Hi jonrsharpe, thank you for the tip. i'm going to look at that right away – John Smith Nov 05 '14 at 14:15
  • 2
    Or you could use dict comprehension: http://stackoverflow.com/questions/15516413/dict-fromkeys-all-point-to-same-list – Roman L Nov 05 '14 at 14:33
  • 1
    Also see: http://stackoverflow.com/questions/23397153/append-value-to-one-list-in-dictionary-appends-value-to-all-lists-in-dictionary – Jon Clements Nov 05 '14 at 14:43

4 Answers4

2

This sort of thing is commonly done with dictionary comprehensions rather thandict.fromkeys():

brands = ['val1', 'val2', 'val3']
infoBrands = {brand: {'nbOffers': 0, 'nbBestOffers': 0, 'higherPrice': []}
                for brand in brands}

infoBrands['val1']['nbOffers'] += 1
print infoBrands

Output:

{'val3': {'higherPrice': [], 'nbOffers': 0, 'nbBestOffers': 0},
 'val2': {'higherPrice': [], 'nbOffers': 0, 'nbBestOffers': 0},
 'val1': {'higherPrice': [], 'nbOffers': 1, 'nbBestOffers': 0}}
martineau
  • 119,623
  • 25
  • 170
  • 301
1

Here is another way of achieving the required result using dict comprehension:

brands = ['val1', 'val2', 'val3']
infoBrands = {g: dict({i: 0 for i in ['nbOffers', 'nbBestOffers']},
                       **{j: [] for j in ['higherPrice']}) for g in brands}

infoBrands['val1']['nbOffers'] += 1
print infoBrands
thunderoy
  • 43
  • 5
0
brands = ['val1', 'val2', 'val3']
init = dict(higher_price=[], nb_offers=0, nb_best_offers=0)
info = {brand: dict(init) for brand in brands}
  • This will make separate dictionaries, but they'll share `higher_price` lists, e.g. `info["val1"]["higher_price"] is info["val2"]["higher_price"]`. – DSM Nov 05 '14 at 15:20
0

Thank you everyone,

EDIT: look at @martineau answer

I did the following:

brands = ['val1', 'val2', 'val3']
infoBrands = dict.fromkeys(brands)

for brand in brands:
    infoBrands[brand] = dict([('nbOffers', 0), ('nbBestOffers', 0), ('higherPrice', [])])                                                                                                                                                     

infoBrands['val1']['nbOffers'] = 1
print infoBrands

Results:

{'val3': {'higherPrice': [], 'nbOffers': 0, 'nbBestOffers': 0}, 'val2': {'higherPrice': [], 'nbOffers': 0, 'nbBestOffers': 0}, 'val1': {'higherPrice': [], 'nbOffers': 1, 'nbBestOffers': 0}}

John Smith
  • 808
  • 3
  • 9
  • 20