How do I extract and edit a dict value without editing the dict itself?
Ust the .copy()
attribute when assigning the fruit
variable.
>>> mydict = {'a': ['apple', 'avocado'],
'b': ['banana', 'berry'],
'c': ['carrot', 'cucumber']}
>>> fruits = mydict['a'].copy()
>>> fruits.pop(0)
This will give the following results
>>> mydict
{'a': ['apple', 'avocado'],
'b': ['banana', 'berry'],
'c': ['carrot', 'cucumber']}
>>> fruits
['avocado']
How to copy a dict and modify it in one line of code
The simplest way in my opinion is something like this:
new_dict = {**old_dict, 'changed_val': value, **other_new_vals_as_dict}
Understanding dict.copy() - shallow or deep?
By "shallow copying" it means the content of the dictionary is not copied by value, but just creating a new reference.
>>> a = {1: [1,2,3]}
>>> b = a.copy()
>>> a, b
({1: [1, 2, 3]}, {1: [1, 2, 3]})
>>> a[1].append(4)
>>> a, b
({1: [1, 2, 3, 4]}, {1: [1, 2, 3, 4]})
In contrast, a deep copy will copy all contents by value.
>>> import copy
>>> c = copy.deepcopy(a)
>>> a, c
({1: [1, 2, 3, 4]}, {1: [1, 2, 3, 4]})
>>> a[1].append(5)
>>> a, c
({1: [1, 2, 3, 4, 5]}, {1: [1, 2, 3, 4]})
So:
b = a
: Reference assignment, Makea
andb
points to the same object.b = a.copy()
: Shallow copying,a
andb
will become two isolated objects, but their contents still share the same referenceb = copy.deepcopy(a)
: Deep copying,a
andb
's structure and content become completely isolated.
Using .copy() to create a copy of a dictionary that can be editing without altering the original dictionary
You want to create a deep copy of the dict, otherwise the objects referenced within the dict will be shared between the original and the shallow copy (hence changing an element in your second example not working how you want):
import copy
dict1 = dict({'a':[1,2,3],'b':[4,5,6],'c':[7,8,9]})
dict2 = copy.deepcopy(dict1)
Nested dictionaries copy() or deepcopy()?
When you're working with a mutable collection like a dictionary or a list, and you perform an assignment, you are not creating a copy of that object by default – i.e., the assignment of some dict b
to another dict a
creates a reference from b
to the original object a
, such that when you mutate b
you indirectly also mutate a
.
See this basic example:
>>> orig = {"a": 1, "b": 2}
>>> new = orig
>>> new["a"] = 9
>>> orig
{'a': 9, 'b': 2}
>>> new
{'a': 9, 'b': 2}
>>> new is orig
True
To fix this and keep the new
and orig
dictionaries separate objects that do not reference each other, make a deepcopy of orig
when assigning it to new
:
>>> import copy
>>> orig = {"a": 1, "b": 2}
>>> new = copy.deepcopy(orig)
>>> new["a"] = 9
>>> orig
{'a': 1, 'b': 2}
>>> new
{'a': 9, 'b': 2}
>>> new is orig
False
Also, here's a tl;dr for the Python documentation linked to above:
Assignment statements in Python do not copy objects, they create bindings between a target and an object. For collections that are mutable or contain mutable items, a copy is sometimes needed so one can change one copy without changing the other.
Assigning a value in a dictionary from another dictionary without pointing to it
You can copy the value (so you doesn't reference the same value) by using the copy()
method:
Originaldic = {"Foo":["Somthing",1], "Bar":["action",2], "baz":["otherthing",6]}
listofplayer = ["Bar","Foo"]
Tempdic = {}
for player in listofplayer:
Tempdic[player] = Originaldic[player].copy()
#the problem is likely at this step above
if Tempdic[player][1]==2:
Tempdic[player].pop(0)
#note: I have to use pop here because in reality I have a list of list but tried simplify the code
Tempdic[player] = ["differentaction",5]
print(Tempdic)
#{'Bar': ['differentaction', 5], 'Foo': ['Somthing', 1]}
print(Originaldic)
#{'Foo': ['Somthing', 1], 'Bar': ['action', 2], 'baz': ['otherthing', 6]}
but you can also use deepcopy
to do a deep copy to make sure that non of the dictionary shares any data:
from copy import deepcopy
Originaldic = {"Foo":["Somthing",1], "Bar":["action",2], "baz":["otherthing",6]}
listofplayer = ["Bar","Foo"]
Tempdic = {}
for player in listofplayer:
Tempdic[player] = deepcopy(Originaldic[player])
#the problem is likely at this step above
if Tempdic[player][1]==2:
Tempdic[player].pop(0)
#note: I have to use pop here because in reality I have a list of list but tried simplify the code
Tempdic[player] = ["differentaction",5]
print(Tempdic)
#{'Bar': ['differentaction', 5], 'Foo': ['Somthing', 1]}
print(Originaldic)
#{'Foo': ['Somthing', 1], 'Bar': ['action', 2], 'baz': ['otherthing', 6]}
Related Topics
How Is Returning the Output of a Function Different from Printing It
How to Sort a List of Dictionaries by a Value of the Dictionary
Flatten an Irregular List of Lists
How to Convert String Representation of List to a List
How to Get Keyboard Input in Pygame
Tkinter Assign Button Command in a For Loop With Lambda
Switch Between Two Frames in Tkinter
Why Is the Order in Dictionaries and Sets Arbitrary
How to Print Without a Newline or Space
Are Dictionaries Ordered in Python 3.6+
Evaluating a Mathematical Expression in a String
How to Parse an Iso 8601-Formatted Date
How to Count the Occurrences of a List Item
Is There a Built in Function For String Natural Sort
Split String Every Nth Character
Reverse/Invert a Dictionary Mapping
Pass Input/Variables to Command/Script Over Ssh Using Python Paramiko