Dictionary where values are dictionaries not updating [duplicate] - python

This question already has answers here:
How to copy a dictionary and only edit the copy
(23 answers)
Closed 1 year ago.
I want to create a dictionary where each value is a dictionary. Here's what I have:
start = 1
for i in range(3):
updated_payload = payload
updated_payload["params"]["dsoJsonData"]["ReadMap"]["Some"]["StartIndex"] = start
x[i] = updated_payload
start = start + 1
Where payload is also a dictionary with all the needed attributes. I am just changing the StartIndex attribute to whatever the loop is at that time. However, when I run this piece of code all my dictionaries' keys have the same exact values. StartIndex all equal to 3. Why are they all getting the same value and how can I fix it so that it gets its respective iteration number?

This is because you're referencing those dicts rather than copying them. So all of your x[i]'s are pointing the same dict. You should be copying them as the following:
x[i] = updated_payload.copy()

I think you need to make a copy of the payload dictionary. You are directly assigning the value of payload to updated_payload so it's passed by reference instead of being copied.
updated_payload = payload.copy()

Related

How to change the specific values within a dictionary of lists in python [duplicate]

This question already has answers here:
How do I clone a list so that it doesn't change unexpectedly after assignment?
(24 answers)
Closed 1 year ago.
This is the worst blocker that I have ever had attempting to learn Python. I spent about 10 hours on this one and could really use help.
I want to have dictionaries hold lists in python and then access and change a specific value in those lists. When I do this the way that seems logical to me and access a key then list value, it actually replaces other key's list values.
If I just assign 100 to the key XList it prints 100 for both XList and YList. Why does assigning to one key effect the other???
And if I uncomment the assignment to YList it prints 254 for both. Why can't I assign itemized values to keys and lists like this? How can I assign specific values to lists within dictionaries and access the main lists via keys?? Why does what seems like changing just one keys list value change both key's lists???
testDictKeys= ['XList', 'YList', 'ZList']
testDict = dict.fromkeys(['XList', 'YList', 'ZList'])
noneFillerList = [None] * 30
#Now fill all the columns and row of the dictionary with zeros
for x in range(0,2):
testDict[testDictKeys[x]] = noneFillerList
for x in range(0, 29):
testDict['XList'][x]=100
#testDict['YList'][x]=254
print (testDict['XList'][0])
print (testDict['YList'][0])
Any help is appreciated.
The problem is that you only create one list and assign every dictionary to contain it. To fix the problem, be sure to create a new list to add to each dictionary.

Why does dict.pop() here remove the value from two dictonaries while specifing only one? [duplicate]

This question already has answers here:
How do I clone a list so that it doesn't change unexpectedly after assignment?
(24 answers)
Closed 2 years ago.
I am writing a program in which I need to iterate through many long dictionaries, so I thought I could remove unneeded values from it, to save on some runtime. Here is a minimal working example with lacking context:
years = {0: 2019, 1: 2020, 2: 2021}
def iterate_years():
for i in years:
temp_years = years
print("years:", years)
print("temp_years:", temp_years)
temp_years.pop(i)
minimum = min(temp_years)
maximum = max(temp_years)
print("temp_years:", years)
print("years:", years)
iterate_years()
When I run this it returns a runtime error because the size f the dictionary changed while iteration. As you can see through the example the line temp_years.pop(i) seems to pop the key-value pair i in temp_years, as specified but also in years.
Why does this happen? I am not very experienced but years is never assigned to temp_years after the pop() so the value for years should stay like they were specified in the first line.
The problem here is that temp_years and years are pointing to the same object in memory (reference), you can check it comparing the id of both variables:
>>> id(temp_years) == id(years)
>>> True
If you want a copy, you have to create a new dict with temp_years = years.copy(). But if you have nested objects in the dictionary, you will have to do a deep copy, because dict.copy() only does a shallow copy.
>>> import copy
>>> temp_years = copy.deepcopy(years)
>>> id(temp_years)
140641196228824
>>> id(years)
140641197662072
You need to make a copy when you create the dict temp_years otherwise it will just function as a pointer to the original object (years). That's why the changes you're making to temp_years also change years. So all you need is to change that assignment line:
temp_years = years.copy()
You could also make it a deepcopy if it's a nested dict (otherwise you'll only get the top level keys):
import copy
temp_years = copy.deepcopy(years)
Check out this answer for more details: How to copy a dictionary and only edit the copy

Iterating and changing elements in a list in Python [duplicate]

This question already has answers here:
Can't modify list elements in a loop [duplicate]
(5 answers)
Closed 4 years ago.
I'm supposed to find the largest number in a list, and then change all the elements of the list to that number. But when I print the output after the iteration, it still hasn't changed. What am I doing wrong please ?
Ar =[5,4,11]
ArMax = max(Ar)
for i in Ar:
i = ArMax
print(Ar)
The list doesn't change because you've done nothing to change the list. Your list is Ar -- where have you assigned a new value to anything in that list? Nowhere. All you did was to create a local variable to take on the values in Ar, and then change the value of that variable. You never touched the original list. Instead, you have to change the list elements themselves, not their copies. Keeping close to your present code:
for i in range(len(Ar)):
Ar[i] = ArMax
Another way would be to create a new list with those items in it, and simply replace the original list all at once:
Ar = [ArMax] * len(Ar)
This looks to see how long the current list is with len(Ar). Then it takes a one-element list with the max value and replicates it that many times. That new list becomes the new value of Ar.
i = ArMax does not actually assign values to the list because the values of i are copies of the elements in the list. If you want to fix this, try:
for i in xrange(len(Ar)):
Ar[i] = ArMax

Strange behaviour when appending items to lists inside dictionaries in python [duplicate]

This question already has answers here:
Dictionary creation with fromkeys and mutable objects. A surprise [duplicate]
(3 answers)
Closed 8 years ago.
I have a dictionary indexed by 201 integer keys (0..200). the value for each of these keys is a list. generated with the code below:
dictionary=dict.fromkeys(range201,[])
i am getting this strange behaviour when i try to append items to the list belonging to one specific index, if i do this:
dictionary[1].append("foo")
i would expect this:
>>dictionary
{0:[], 1:["foo"],2:[],...}
but instead i end up with this:
>>dictionary
{0:["foo"], 1:["foo"],2:["foo"],...}
to clarify a bit the context in which the operation is performed, i am enumerating a list of values that can be None or float, i want to skip the None and append the float to the list corresponding to the enumerate index:
for i, value in enumerate(valuesList):
if value is None:
continue
dictionary[i].append(value)
this is behaviour is independent of which integer index i use, and i end up with the same values at all indices. I could use a list of lists and achieve the same result i think. but i wanted to understand this behaviour.
This is the normal behavior. All the entry of your dictionary where initialized with a reference to the same list. So when appending an element using one key, as all the key are pointing the same list, the modification is applied to all the entries of the dic.
Try this instead :
dictionary={}
for i in range(201):
#the loop make the list.__init__() (i.e. the []) being called 200 times
dictionary[i] = []
dictionary[1].append("foo")
print dictionary

How to get a copy from a list? [duplicate]

This question already has answers here:
How do I clone a list so that it doesn't change unexpectedly after assignment?
(24 answers)
Closed 9 years ago.
I am trying to get an element from list and make some change on this element (which is also a list). Weirdly, the change applied on the previous list. Here is my code:
>>>sentences[0]
['<s>/<s>',
'I/PRP',
'need/VBP',
'to/TO',
'have/VB',
'dinner/NN',
'served/VBN',
'</s>/</s>']
>>>sentence = sentences[0]
>>>sentence.insert(0,startc); sentence.append(endc)
>>>sentences[0]
['<s>/<s>',
'<s>/<s>',
'I/PRP',
'need/VBP',
'to/TO',
'have/VB',
'dinner/NN',
'served/VBN',
'</s>/</s>'
'</s>/</s>']
It is like I just got a pointer to that element, not a copy
You do get a "pointer", in fact. Lists (and any mutable value type!) are passed around as reference in Python.
You can make a copy of a list by passing it to the list() object constructor, or by making a full slice using [:].
a = [1,2,3]
b = a
c = list(a)
d = a[:]
a[1] = 4 # changes the list referenced by both 'a' and 'b', but not 'c' or 'd'
You're exactly right! In Python, when you pass a list as an argument to a function, or you assign a list to another variable, you're actually passing a pointer to it.
This is for efficiency reasons; if you made a separate copy of a 1000-item list every time you did one of the aforementioned things, the program would consume way too much memory and time.
To overcome this in Python, you can duplicate a one-dimensional list using = originalList[:] or = list(originalList):
sentence = sentences[0][:] # or sentence = list(sentences[0])
sentence.insert(0,startc)
sentence.append(endc)
print(sentence) # modified
print(sentences[0]) # not modified
Consider using list comprehension if you need to duplicate a 2D list.

Categories