0

I am missing something small here, and cannot for the life of me figure it out. I am trying to overwrite a dictionary value at a specific index. So for example:

dict={}
values1 = [5,10,20]
values2 = [30,40,50]
dict['key1'] = values1
dict['key2'] = values2
print(dict['key1'])
print(dict['key2'])
dict['key1'][1] = 15
print(dict['key1'])
print(dict['key2'])

returns:

[5, 10, 20]
[30, 40, 50]
[5, 15, 20]
[30, 40, 50]

Exactly as expected, it overwrote the first key, and index 1 with 15, perfect.

So why does this code below not work the same??

technicianOutput={}
monthNumList = [2,3,4,5,6]
zeroList = []
staffList = ['joe blow', 'john doe']
for x in range(len(monthNumList)):
    zeroList.append(0)
for tech in staffList:
    technicianOutput[tech] = zeroList
print(technicianOutput)
technicianOutput['joe blow'][0] = 1
technicianOutput['john doe'][1] = 1
print(technicianOutput)

returns:

{'joe blow': [0, 0, 0, 0, 0], 'john doe': [0, 0, 0, 0, 0]}
{'joe blow': [1, 1, 0, 0, 0], 'john doe': [1, 1, 0, 0, 0]}

I am expecting:

{'joe blow': [0, 0, 0, 0, 0], 'john doe': [0, 0, 0, 0, 0]}
{'joe blow': [1, 0, 0, 0, 0], 'john doe': [0, 1, 0, 0, 0]}
martineau
  • 119,623
  • 25
  • 170
  • 301
MattG
  • 1,682
  • 5
  • 25
  • 45
  • 4
    Both items in your dictionary refer to the same list `zeroList`. When you change the list, you observe the same change in both items. – DYZ May 05 '20 at 21:10
  • 2
    `technicianOutput[tech] = zeroList` is **not** making a copy of `zeroList`, so after the loop all entries refer to the same list. – martineau May 05 '20 at 21:11
  • 2
    Does this answer your question? [List of lists changes reflected across sublists unexpectedly](https://stackoverflow.com/questions/240178/list-of-lists-changes-reflected-across-sublists-unexpectedly). Talks about list of lists and not dict with lists, but the same idea holds (there might be a better dup out there) – Tomerikoo May 05 '20 at 21:12
  • 1
    `technicianOutput = {tech: [0 for month in monthNumList] for tech in staffList}` this is a dictionary comprehension, a very pythonic way to declare data structures and does in one line what two for loops can do – bherbruck May 05 '20 at 21:21
  • 1
    You can make a shallow copy of a list using its `copy()` method. i.e. `technicianOutput[tech] = zeroList.copy()`. You can also use slicing to do it: i.e. `technicianOutput[tech] = zeroList[:]`. – martineau May 05 '20 at 21:31
  • The article [Facts and myths about Python names and values](https://nedbatchelder.com/text/names.html) has a good explanation of the differences between the two and how they relate to one another. – martineau May 07 '20 at 19:26

2 Answers2

3

Both technicianOutput['joe blow'] and technicianOutput['john doe'] point to the same object: zeroList. You need to make sure that you have two different instances of lists containing zeros. For example:

for tech in staffList:
    technicianOutput[tech] = [0] * len(monthNumList)

or via explicit copy

zeroList = [0] * len(monthNumList)
for tech in staffList:
    technicianOutput[tech] = list(zeroList)
Lesiak
  • 22,088
  • 2
  • 41
  • 65
1

Explication of your problem is in comment of DYZ. To correct it you have to change :

for x in range(len(monthNumList)):
    zeroList.append(0)
for tech in staffList:
    technicianOutput[tech] = zeroList

By:

for tech in staffList:
    technicianOutput[tech] = [0]*len(monthNumList)
Renaud
  • 2,709
  • 2
  • 9
  • 24