1410

I set dict2 = dict1. When I edit dict2, the original dict1 also changes. Why?

>>> dict1 = {"key1": "value1", "key2": "value2"}
>>> dict2 = dict1
>>> dict2["key2"] = "WHY?!"
>>> dict1
{'key2': 'WHY?!', 'key1': 'value1'}
Mateen Ulhaq
  • 24,552
  • 19
  • 101
  • 135
MadSc13ntist
  • 19,820
  • 8
  • 25
  • 19
  • 15
    [PythonTutor](http://pythontutor.com) is great for visualizing Python references. [Here's this code at the last step](http://pythontutor.com/visualize.html#code=dict1%20%3D%20%7B%22key1%22%3A%20%22value1%22,%20%22key2%22%3A%20%22value2%22%7D%0Adict2%20%3D%20dict1%0Adict2%5B%22key2%22%5D%20%3D%20%22WHY%3F!%22%0A&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false). You can see `dict1` and `dict2` point to the same dict. – wjandrea Aug 09 '19 at 13:54
  • 4
    Just in case PythonTutor goes down, here's [a screenshot](https://i.stack.imgur.com/pCekS.png) of the data structures at the end. – wjandrea Aug 06 '21 at 21:54

23 Answers23

1372

Python never implicitly copies objects. When you set dict2 = dict1, you are making them refer to the same exact dict object, so when you mutate it, all references to it keep referring to the object in its current state.

If you want to copy the dict (which is rare), you have to do so explicitly with

dict2 = dict(dict1)

or

dict2 = dict1.copy()
Mike Graham
  • 73,987
  • 14
  • 101
  • 130
  • 53
    It might be better to say "dict2 and dict1 point to the **same** dictionary", you are not changing dict1 or dict2 but what they point to. – GrayWizardx Mar 17 '10 at 21:15
  • 1
    @GrayWizardx, I am not sure what you are suggesting. You think I should use the term "dictionary" instead of "dict object"? – Mike Graham Mar 17 '10 at 21:17
  • 5
    No I was saying that its a pointer thing, but then I tried to rewrite it without sounding like a curmudgeony old C++ programmer telling people that new languages suck. Its a common problem for people learning c++ as well. Your answer is perfect as is, and I already +1'ed it. – GrayWizardx Mar 17 '10 at 21:45
  • 456
    Also note that the dict.copy() is shallow, if there is a nested list/etc in there changes will be applied to both. IIRC. Deepcopy will avoid that. – Will Mar 18 '10 at 07:08
  • 28
    It is not quite correct that python never implicitly copies objects. Primitive data types, such as int, float, and bool, are also treated as objects (just do a `dir(1)` to see that), but they are implicitly copied. – daniel kullmann Mar 06 '12 at 10:34
  • 28
    @danielkullmann, I think you might have misunderstandings about Python based on how other languages you've dealt with work. In Python, a) There is no concept of "primitive data types". `int`, `float`, and `bool` instances are real Python objects, and b) objects of these types are not implicitly copied when you pass them, not at a semantic Python level for sure and not even as an implementation detail in CPython. – Mike Graham Mar 06 '12 at 15:03
  • 1
    Another possibility: `dict2 = copy.copy(dict1)` ([documentation](http://docs.python.org/2/library/copy.html#copy.copy)) – Adam Rosenfield Nov 15 '12 at 21:04
  • 5
    I recommend doing your best to forget the `copy` module exists. – Mike Graham Nov 15 '12 at 22:13
  • 5
    Note that using `dict1.copy()` will ensure your resulting type is the same as `dict1` when necessary. This may be important, e.g. when using `OrderedDict` – Joe Jan 12 '13 at 23:51
  • 5
    Use deepcopy if your dictionary is multiple layers deep and you want a completely independent copy... otherwise dcopy = d.copy(); dcopy['top']['nested']['bottom'] = 1 will change the object referred to by d['top']['nested']['bottom'] as well. This burned me when trying to apply a range of offsets for a batch analysis to a value in a data structure inside a loop... my offsets were acting cumulatively because they were affecting the original as well as the copy. – flutefreak7 Apr 12 '14 at 22:59
  • 2
    Be **very** careful when you use `copy.deepcopy` -- it's very easy to introduce silent bugs. It can and should be avoided the vast majority of the time. – Mike Graham Apr 13 '14 at 18:42
  • 3
    @MikeGraham could you mention why you say it is 'rare' to copy a dict? – user-2147482637 Oct 07 '14 at 07:15
  • 2
    @user1938107, More often you build a dict with the differences you want rather than copying the dict then mutating it. – Mike Graham Oct 11 '14 at 15:26
  • 14
    @MikeGraham: Could you point to some examples of silent bugs from deepcopy? Something to do with sub-objects not copying properly? – naught101 Sep 10 '15 at 00:34
  • So if I want to call a function that is not allowed to change the dict, I'd like to call `function(dict(myDict))`. But now changes in `function` to the input still apply to `myDict`. Am I doing it wrong? – DiCaprio Sep 11 '15 at 10:47
  • 3
    What about a deep copy? What if I want to copy a dictionary of dictionaries? In that case, you would need `dict2 = copy.deepcopy(dict1)` from `import copy` – orezvani Aug 14 '16 at 12:06
  • 2
    @MikeGraham: Same question as naught101: what bugs might arise from using deepcopy? – Arco Bast Aug 24 '16 at 14:04
  • @MikeGraham: When you say more often you build a dict with the differences... So are you saying you use a dict that automatically links back to the original dict for fields that didn't change? Isn't it simpler to just copy the dict in such cases? – personal_cloud Sep 16 '17 at 22:38
  • @naught101: It's very easy to accidentally copy too deep - there's often a point at which you want to stop copying. The cyclic reference handling is also kind of ad hoc and not as reliable as the docs would have you believe. One not-so-silent example is what happens if you try to deepcopy a [self-referential OrderedDict](https://ideone.com/PeX968) on Python 2. – user2357112 Sep 16 '17 at 23:44
  • 2
    @user2357112: haha... that looks like a well-deserved runtime error. I can't see how something like that would ever end well, or be a good idea to start with :P – naught101 Sep 18 '17 at 01:57
  • @naught101: The thing is, `copy.deepcopy` *claims* it doesn't have problems with reference loops. – user2357112 Sep 18 '17 at 02:28
  • @user2357112: that code actually works fine on python 3.6.1... Still seems like a bad idea. – naught101 Sep 19 '17 at 04:01
  • @naught101 I would also recommend to avoid deep-copying, not to avoid implementation errors in a library but to avoid design error in your own code. Copying is an expensive operation, and editing in-place or storing changes is often much faster (unless you really need fast access to the history of your object, but even then full copying is not necessary, see Redux). Another reason is that by copying you lose the single truth of source: all copies need to be updated for changes, and this can easily go inconsistent. As a rule of thumb, copy only if you can't control the code you share data with. – Kirill Bulygin Oct 02 '17 at 17:35
  • 134
    Unsubstantiated rhetoric like "Deep copy is considered harmful" is unhelpful. All else being equal, shallow copying a complex data structure is *significantly* more likely to yield unexpected edge case issues than deep copying the same structure. A copy in which modifications modify the original object isn't a copy; it's a bug. Ergo, most use cases absolutely *should* call `copy.deepcopy()` rather than `dict()` or `dict.copy()`. [Imran](https://stackoverflow.com/users/1897/imran)'s [concise answer](https://stackoverflow.com/a/2465951/2809027) is on the right side of sanity, unlike this answer. – Cecil Curry Dec 05 '17 at 03:39
  • 2
    @CecilCurry: the proper answer is to understand how the Python object model works, of course. I recommend people read [Ned Batchelder's article on Python names](https://nedbatchelder.com/text/names.html), so they can make their own informed decision on what kind of copying they need. Sometimes the answer is not to copy at all, or to use a loop with shallow copying. – Martijn Pieters Mar 06 '18 at 10:16
  • 1
    Both solutions didn't work for me, but `deep.copy()` worked – otayeby Mar 16 '18 at 02:17
  • 1
    Usually you copy a dictionary in order to change it. In that case, both shallow copy methods fails, you need `dict2 = copy.deepcopy(dict1)`. – shahar_m Apr 25 '18 at 11:02
  • 2
    this answer is incorrect. The "deepcopy" answer is correct. Using a shallow copy is not a valid solution to the problem/question asked – Hugo Mar 19 '20 at 14:05
  • 2
    @Hugo: It's a perfectly adequate solution for the OP's case, because both keys and values are immutable types; deep copying wouldn't improve it in any way (it won't even change the behavior; the "deep copy" of `str` is the identity function, it doesn't actually copy it, so shallow and deep copies are *identical* in end result here). I 100% agree that `deepcopy` is the safer solution when the values might be mutable types, but don't call this answer incorrect when it's 100% correct for the OP's specific use case. – ShadowRanger Nov 24 '20 at 21:28
  • 1
    The question is "How to copy a dictionary and only edit the copy?" and shallow copy is not a correct answer. Shallow copy works for the example given in the question but that is just an edge case where the dict is flat. @MikeGraham should edit his answer. – Hugo Nov 25 '20 at 09:37
  • 2
    This original answer based on the question asked is not just wrong, but dangerous. Say you had a module-level dictionary, effectively global, as a template that you want to modify in 1 or more functions when repeatedly called in different ways. As Cecil Curry and others say, a deep copy is the only way. After 11 years, I'd suggest this answer is taken down. There are also plenty of answers below that will still leave someone with a reference to the original dictionary when doing a supposed copy. If someone is in a hurry, they might not be reading these comments. – Jim Bob May 17 '21 at 20:48
1133

When you assign dict2 = dict1, you are not making a copy of dict1, it results in dict2 being just another name for dict1.

To copy the mutable types like dictionaries, use copy / deepcopy of the copy module.

import copy

dict2 = copy.deepcopy(dict1)
Imran
  • 87,203
  • 23
  • 98
  • 131
  • 142
    For any dictionary I ever work with, deepcopy is what I need... I just lost several hours due to a bug that was because I wasn't getting a complete copy of a nested dictionary and my changes to nested entries were affecting the original. – flutefreak7 Apr 12 '14 at 23:01
  • 15
    Same here. deepcopy() does the trick. Was messing up my nested dicts inside a rotating cache by adding a timestamp to a 'copy' of the original event. Thank you! – fxstein Feb 10 '15 at 03:05
  • 17
    This actually should be marked as the correct answer; This answer is general and it works for a dictionary of dictionaries as well. – orezvani Aug 14 '16 at 12:09
  • 75
    **This should be the accepted answer.** The unsubstantiated "Deep copy is considered harmful" rhetoric embedded in the comment section of the current [accepted answer](https://stackoverflow.com/a/2465932/2809027) blatantly invites synchronization woes when copying nested dictionaries (such as those documented here) and should be challenged as such. – Cecil Curry Dec 05 '17 at 03:44
  • 1
    deepcopy is the way to go in case of a complex dictionary structure. dict1.copy() simply copies the values of keys as references and not as objects. – Rohith N Mar 02 '20 at 13:51
  • 4
    Thank you, deepcopy() was what I needed! Seems a bit odd that copy() still holds refs to the original, but hey ho. – Harry Jul 15 '20 at 11:16
  • If you control the code using the dictionary, and the intent is that it, or any of the mutable objects it contains, not be altered, an appropriate code hint to warn developers would be useful (how?), or, use an "immutable" class that inhibits the normal means of modifying attributes (see: https://stackoverflow.com/questions/3711657/can-i-prevent-modifying-an-object-in-python). If the intent is for a dictionary to be a kind of template with the intent that it be mutated, then either deep copy, or a factory method return an object or dictionary of the right kind. – Jacob Lee Jul 21 '21 at 16:47
  • i was using this dict2 = dict1.copy() but copy function was actually coping the object, but your solution works! thank you! – shailu Sep 09 '21 at 14:08
295

While dict.copy() and dict(dict1) generates a copy, they are only shallow copies. If you want a deep copy, copy.deepcopy(dict1) is required. An example:

>>> source = {'a': 1, 'b': {'m': 4, 'n': 5, 'o': 6}, 'c': 3}
>>> copy1 = source.copy()
>>> copy2 = dict(source)
>>> import copy
>>> copy3 = copy.deepcopy(source)
>>> source['a'] = 10  # a change to first-level properties won't affect copies
>>> source
{'a': 10, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}
>>> copy1
{'a': 1, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}
>>> copy2
{'a': 1, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}
>>> copy3
{'a': 1, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}
>>> source['b']['m'] = 40  # a change to deep properties WILL affect shallow copies 'b.m' property
>>> source
{'a': 10, 'c': 3, 'b': {'m': 40, 'o': 6, 'n': 5}}
>>> copy1
{'a': 1, 'c': 3, 'b': {'m': 40, 'o': 6, 'n': 5}}
>>> copy2
{'a': 1, 'c': 3, 'b': {'m': 40, 'o': 6, 'n': 5}}
>>> copy3  # Deep copy's 'b.m' property is unaffected
{'a': 1, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}

Regarding shallow vs deep copies, from the Python copy module docs:

The difference between shallow and deep copying is only relevant for compound objects (objects that contain other objects, like lists or class instances):

  • A shallow copy constructs a new compound object and then (to the extent possible) inserts references into it to the objects found in the original.
  • A deep copy constructs a new compound object and then, recursively, inserts copies into it of the objects found in the original.
ingyhere
  • 11,818
  • 3
  • 38
  • 52
gpanda
  • 3,282
  • 1
  • 14
  • 13
  • 3
    this should be the right answer as it doesn't to explicitly loop over the dict and can be used for other primary structures. – Nikkolasg Jan 22 '15 at 12:23
  • 38
    Just to clarify: `w=copy.deepcopy(x)` is the key line. – alcoholiday Sep 23 '15 at 14:06
  • What is the difference between `dict2 = dict1` and `dict2 = copy.deepcopy(dict1)` ? – TheTank Jun 01 '18 at 14:41
  • 1
    @TheTank, y=x makes the two names(references) refer to a same object, i.e. "y is x" is True. Any change made on the object through x is equivalent to a same change through y. However u, v, w are references to new different objects which have values copied from x during instantiation though. As for the differences between u,v(shallow copy) and w(deepcopy), please check https://docs.python.org/2/library/copy.html – gpanda Jun 02 '18 at 08:32
106

In Depth and an easy way to remember:

Whenever you do dict2 = dict1, dict2 refers to dict1. Both dict1 and dict2 points to the same location in the memory. This is just a normal case while working with mutable objects in python. When you are working with mutable objects in python you must be careful as it is hard to debug.

Instead of using dict2 = dict1, you should be using copy(shallow copy) and deepcopy method from python's copy module to separate dict2 from dict1.

The correct way is:

>>> dict1 = {"key1": "value1", "key2": "value2"}
>>> dict2 = dict1.copy()
>>> dict2
{'key1': 'value1', 'key2': 'value2'}
>>> dict2["key2"] = "WHY?"
>>> dict2
{'key1': 'value1', 'key2': 'WHY?'}
>>> dict1
{'key1': 'value1', 'key2': 'value2'}
>>> id(dict1)
140641178056312
>>> id(dict2)
140641176198960
>>> 

As you can see the id of both dict1 and dict2 are different, which means both are pointing/referencing to different locations in the memory.

This solution works for dictionaries with immutable values, this is not the correct solution for those with mutable values.

Eg:

>>> import copy
>>> dict1 = {"key1" : "value1", "key2": {"mutable": True}}
>>> dict2 = dict1.copy()
>>> dict2
{'key1': 'value1', 'key2': {'mutable': True}}
>>> dict2["key2"]["mutable"] = False
>>> dict2
{'key1': 'value1', 'key2': {'mutable': False}}
>>> dict1
{'key1': 'value1', 'key2': {'mutable': False}}
>>> id(dict1)
140641197660704
>>> id(dict2)
140641196407832
>>> id(dict1["key2"])
140641176198960
>>> id(dict2["key2"])
140641176198960

You can see that even though we applied copy for dict1, the value of mutable is changed to false on both dict2 and dict1 even though we only change it on dict2. This is because we changed the value of a mutable dict part of the dict1. When we apply a copy on dict, it will only do a shallow copy which means it copies all the immutable values into a new dict and does not copy the mutable values but it will reference them.

The ultimate solution is to do a deepycopy of dict1 to completely create a new dict with all the values copied, including mutable values.

>>>import copy
>>> dict1 = {"key1" : "value1", "key2": {"mutable": True}}
>>> dict2 = copy.deepcopy(dict1)
>>> dict2
{'key1': 'value1', 'key2': {'mutable': True}}
>>> id(dict1)
140641196228824
>>> id(dict2)
140641197662072
>>> id(dict1["key2"])
140641178056312
>>> id(dict2["key2"])
140641197662000
>>> dict2["key2"]["mutable"] = False
>>> dict2
{'key1': 'value1', 'key2': {'mutable': False}}
>>> dict1
{'key1': 'value1', 'key2': {'mutable': True}}

As you can see, id's are different, it means that dict2 is completely a new dict with all the values in dict1.

Deepcopy needs to be used if whenever you want to change any of the mutable values without affecting the original dict. If not you can use shallow copy. Deepcopy is slow as it works recursively to copy any nested values in the original dict and also takes extra memory.

Vkreddy
  • 1,618
  • 1
  • 16
  • 13
82

On python 3.5+ there is an easier way to achieve a shallow copy by using the ** unpackaging operator. Defined by Pep 448.

>>>dict1 = {"key1": "value1", "key2": "value2"}
>>>dict2 = {**dict1}
>>>print(dict2)
{'key1': 'value1', 'key2': 'value2'}
>>>dict2["key2"] = "WHY?!"
>>>print(dict1)
{'key1': 'value1', 'key2': 'value2'}
>>>print(dict2)
{'key1': 'value1', 'key2': 'WHY?!'}

** unpackages the dictionary into a new dictionary that is then assigned to dict2.

We can also confirm that each dictionary has a distinct id.

>>>id(dict1)
 178192816

>>>id(dict2)
 178192600

If a deep copy is needed then copy.deepcopy() is still the way to go.

PabTorre
  • 2,878
  • 21
  • 30
54

The best and the easiest ways to create a copy of a dict in both Python 2.7 and 3 are...

To create a copy of simple(single-level) dictionary:

1. Using dict() method, instead of generating a reference that points to the existing dict.

my_dict1 = dict()
my_dict1["message"] = "Hello Python"
print(my_dict1)  # {'message':'Hello Python'}

my_dict2 = dict(my_dict1)
print(my_dict2)  # {'message':'Hello Python'}

# Made changes in my_dict1 
my_dict1["name"] = "Emrit"
print(my_dict1)  # {'message':'Hello Python', 'name' : 'Emrit'}
print(my_dict2)  # {'message':'Hello Python'}

2. Using the built-in update() method of python dictionary.

my_dict2 = dict()
my_dict2.update(my_dict1)
print(my_dict2)  # {'message':'Hello Python'}

# Made changes in my_dict1 
my_dict1["name"] = "Emrit"
print(my_dict1)  # {'message':'Hello Python', 'name' : 'Emrit'}
print(my_dict2)  # {'message':'Hello Python'}

To create a copy of nested or complex dictionary:

Use the built-in copy module, which provides a generic shallow and deep copy operations. This module is present in both Python 2.7 and 3.*

import copy

my_dict2 = copy.deepcopy(my_dict1)
Akay Nirala
  • 1,136
  • 7
  • 13
  • 6
    I believe `dict()` creates a shallow copy not a deep copy. Meaning that if you have a nested `dict` then the outer `dict` will be a copy but the inner dict will be a reference to the original inner dict. – shmuels Jul 10 '18 at 15:13
  • @shmuels yes, both of these methods will create a shallow copy, not the deep one. See, the updated answer. – Akay Nirala Jul 16 '18 at 14:12
40

You can also just make a new dictionary with a dictionary comprehension. This avoids importing copy.

dout = dict((k,v) for k,v in mydict.items())

Of course in python >= 2.7 you can do:

dout = {k:v for k,v in mydict.items()}

But for backwards compat., the top method is better.

Dashing Adam Hughes
  • 1,522
  • 1
  • 13
  • 12
  • 4
    This is particularly useful if you want more control over how and what exactly is copied. +1 – ApproachingDarknessFish Jan 26 '15 at 05:43
  • 15
    Note that this method does not perform a deep copy, and if you want a shallow copy with no need to control over keys to be copied, `d2 = dict.copy(d1)` doesn't require any imports either. – Jarek Piórkowski Aug 23 '15 at 23:23
  • 1
    @JarekPiórkowski: or you can call a method like a method: `d2 = d1.copy()` – Azat Ibrakov Nov 24 '18 at 07:50
  • Note that you don't need the comprehension in the first example. `dict.items` already returns a key/value pair iterable. So you can just use `dict(mydict.items())` (you can also just use `dict(mydict)`). It may be useful to have the comprehension if you wanted to filter the entries. – Paul Rooney May 11 '20 at 23:39
34

In addition to the other provided solutions, you can use ** to integrate the dictionary into an empty dictionary, e.g.,

shallow_copy_of_other_dict = {**other_dict}.

Now you will have a "shallow" copy of other_dict.

Applied to your example:

>>> dict1 = {"key1": "value1", "key2": "value2"}
>>> dict2 = {**dict1}
>>> dict2
{'key1': 'value1', 'key2': 'value2'}
>>> dict2["key2"] = "WHY?!"
>>> dict1
{'key1': 'value1', 'key2': 'value2'}
>>>

Pointer: Difference between shallow and deep copys

d4rty
  • 3,970
  • 5
  • 34
  • 73
22

Assignment statements in Python do not copy objects, they create bindings between a target and an object.

so, dict2 = dict1, it results another binding between dict2and the object that dict1 refer to.

if you want to copy a dict, you can use the copy module. The copy module has two interface:

copy.copy(x)
Return a shallow copy of x.

copy.deepcopy(x)
Return a deep copy of x.

The difference between shallow and deep copying is only relevant for compound objects (objects that contain other objects, like lists or class instances):

A shallow copy constructs a new compound object and then (to the extent possible) inserts references into it to the objects found in the original.

A deep copy constructs a new compound object and then, recursively, inserts copies into it of the objects found in the original.

For example, in python 2.7.9:

>>> import copy
>>> a = [1,2,3,4,['a', 'b']]
>>> b = a
>>> c = copy.copy(a)
>>> d = copy.deepcopy(a)
>>> a.append(5)
>>> a[4].append('c')

and the result is:

>>> a
[1, 2, 3, 4, ['a', 'b', 'c'], 5]
>>> b
[1, 2, 3, 4, ['a', 'b', 'c'], 5]
>>> c
[1, 2, 3, 4, ['a', 'b', 'c']]
>>> d
[1, 2, 3, 4, ['a', 'b']]
loosen
  • 321
  • 2
  • 4
15

You can copy and edit the newly constructed copy in one go by calling the dict constructor with additional keyword arguments:

>>> dict1 = {"key1": "value1", "key2": "value2"}
>>> dict2 = dict(dict1, key2="WHY?!")
>>> dict1
{'key2': 'value2', 'key1': 'value1'}
>>> dict2
{'key2': 'WHY?!', 'key1': 'value1'}
Frerich Raabe
  • 90,689
  • 19
  • 115
  • 207
12

This confused me too, initially, because I was coming from a C background.

In C, a variable is a location in memory with a defined type. Assigning to a variable copies the data into the variable's memory location.

But in Python, variables act more like pointers to objects. So assigning one variable to another doesn't make a copy, it just makes that variable name point to the same object.

Craig McQueen
  • 41,871
  • 30
  • 130
  • 181
  • 6
    python variables act more like c++ references – Ruggero Turra Mar 18 '10 at 08:58
  • 7
    Because everything in Python is an object! http://www.diveintopython.net/getting_to_know_python/everything_is_an_object.html (yes, this response is many years late, but perhaps it's of some use to someone!) – grimman Nov 23 '13 at 12:24
  • 2
    I believe that Python language semantics say there are no "variables". They are called "named references"; meaning the reference to an object is a syntactic string in code. An object can have many named references to it. Immutable objects like ints and floats and str instances have only one instance of it per process. An int of 1 in memory does not change to a 2 or some other value at the same memory address when you do this myvalue=1 myvalue=2 – DevPlayer Jun 24 '16 at 02:03
11

dict1 is a symbol that references an underlying dictionary object. Assigning dict1 to dict2 merely assigns the same reference. Changing a key's value via the dict2 symbol changes the underlying object, which also affects dict1. This is confusing.

It is far easier to reason about immutable values than references, so make copies whenever possible:

person = {'name': 'Mary', 'age': 25}
one_year_later = {**person, 'age': 26}  # does not mutate person dict

This is syntactically the same as:

one_year_later = dict(person, age=26)
Petrus Theron
  • 27,855
  • 36
  • 153
  • 287
8

Every variable in python (stuff like dict1 or str or __builtins__ is a pointer to some hidden platonic "object" inside the machine.

If you set dict1 = dict2,you just point dict1 to the same object (or memory location, or whatever analogy you like) as dict2. Now, the object referenced by dict1 is the same object referenced by dict2.

You can check: dict1 is dict2 should be True. Also, id(dict1) should be the same as id(dict2).

You want dict1 = copy(dict2), or dict1 = deepcopy(dict2).

The difference between copy and deepcopy? deepcopy will make sure that the elements of dict2 (did you point it at a list?) are also copies.

I don't use deepcopy much - it's usually poor practice to write code that needs it (in my opinion).

wisty
  • 6,981
  • 1
  • 30
  • 29
  • I just realized I need to always be using deepcopy so that when I copy a nested dictionary and start modifying nested entries, the effects occur only on the copy and not the original. – flutefreak7 Apr 12 '14 at 23:04
7
>>> dict2 = dict1
# dict2 is bind to the same Dict object which binds to dict1, so if you modify dict2, you will modify the dict1

There are many ways to copy Dict object, I simply use

dict_1 = {
           'a':1,
           'b':2
         }
dict_2 = {}
dict_2.update(dict_1)
imcaozi
  • 117
  • 1
  • 2
  • 14
    `dict_2 = dict_1.copy()` is much more efficient and logical. – Jean-François Fabre Jan 02 '19 at 14:40
  • 3
    Note that if you have a dict inside dict1, with dict_1.copy() the changes you do on the inner dict in dict_2 are also applied to the inner dict in dict_1. In this case you should use copy.deepcopy(dict_1) instead. – queise Apr 15 '19 at 17:27
6

dict2 = dict1 does not copy the dictionary. It simply gives you the programmer a second way (dict2) to refer to the same dictionary.

3

the following code, which is on dicts which follows json syntax more than 3 times faster than deepcopy

def CopyDict(dSrc):
    try:
        return json.loads(json.dumps(dSrc))
    except Exception as e:
        Logger.warning("Can't copy dict the preferred way:"+str(dSrc))
        return deepcopy(dSrc)
xaxxon
  • 19,189
  • 5
  • 50
  • 80
2

for nested dictionay do not use dict(srcData) or srcData.copy() or {**srcData} because if you change second level and more it will also modify source dictionary

srcData = {
  'first': {
    'second': 'second Value'
  }
}
newData = dict(srcData) # srcData.copy() or {**srcData}
newData['first']['second'] = 'new Second Value'

print(srcData)
print(newData)

# it will print
# srcData: {'first': {'second': 'new Second Value'}}
# newData:{'first': {'second': 'new Second Value'}}

# but it should be
# srcData: {'first': {'second': 'second Value'}}
# newData:{'first': {'second': 'new Second Value'}}

another option for deepcopy is using json trick like Javascript JSON.parse(JSON.stringify(obj))

import json

srcData = {'first': {'second': 'second Value'}}
newData = json.loads(json.dumps(srcData))
newData['first']['second'] = 'new Second Value'

print(srcData)
print(newData)

# srcData: {'first': {'second': 'second Value'}}
# newData: {'first': {'second': 'new Second Value'}}
uingtea
  • 6,002
  • 2
  • 26
  • 40
1

As others have explained, the built-in dict does not do what you want. But in Python2 (and probably 3 too) you can easily create a ValueDict class that copies with = so you can be sure that the original will not change.

class ValueDict(dict):

    def __ilshift__(self, args):
        result = ValueDict(self)
        if isinstance(args, dict):
            dict.update(result, args)
        else:
            dict.__setitem__(result, *args)
        return result # Pythonic LVALUE modification

    def __irshift__(self, args):
        result = ValueDict(self)
        dict.__delitem__(result, args)
        return result # Pythonic LVALUE modification

    def __setitem__(self, k, v):
        raise AttributeError, \
            "Use \"value_dict<<='%s', ...\" instead of \"d[%s] = ...\"" % (k,k)

    def __delitem__(self, k):
        raise AttributeError, \
            "Use \"value_dict>>='%s'\" instead of \"del d[%s]" % (k,k)

    def update(self, d2):
        raise AttributeError, \
            "Use \"value_dict<<=dict2\" instead of \"value_dict.update(dict2)\""


# test
d = ValueDict()

d <<='apples', 5
d <<='pears', 8
print "d =", d

e = d
e <<='bananas', 1
print "e =", e
print "d =", d

d >>='pears'
print "d =", d
d <<={'blueberries': 2, 'watermelons': 315}
print "d =", d
print "e =", e
print "e['bananas'] =", e['bananas']


# result
d = {'apples': 5, 'pears': 8}
e = {'apples': 5, 'pears': 8, 'bananas': 1}
d = {'apples': 5, 'pears': 8}
d = {'apples': 5}
d = {'watermelons': 315, 'blueberries': 2, 'apples': 5}
e = {'apples': 5, 'pears': 8, 'bananas': 1}
e['bananas'] = 1

# e[0]=3
# would give:
# AttributeError: Use "value_dict<<='0', ..." instead of "d[0] = ..."

Please refer to the lvalue modification pattern discussed here: Python 2.7 - clean syntax for lvalue modification. The key observation is that str and int behave as values in Python (even though they're actually immutable objects under the hood). While you're observing that, please also observe that nothing is magically special about str or int. dict can be used in much the same ways, and I can think of many cases where ValueDict makes sense.

personal_cloud
  • 3,943
  • 3
  • 28
  • 38
0

i ran into a peculiar behavior when trying to deep copy dictionary property of class w/o assigning it to variable

new = copy.deepcopy(my_class.a) doesn't work i.e. modifying new modifies my_class.a

but if you do old = my_class.a and then new = copy.deepcopy(old) it works perfectly i.e. modifying new does not affect my_class.a

I am not sure why this happens, but hope it helps save some hours! :)

Anushk
  • 482
  • 4
  • 20
0

If your dict is typed as a Mapping, you can't .copy() it, but you can

dict2 = dict1 | {}

It's slightly cryptic, and I can't speak for performance compared to copy.copy(dict1), but it's very terse.

joel
  • 6,359
  • 2
  • 30
  • 55
-3

Copying by using a for loop:

orig = {"X2": 674.5, "X3": 245.0}

copy = {}
for key in orig:
    copy[key] = orig[key]

print(orig) # {'X2': 674.5, 'X3': 245.0}
print(copy) # {'X2': 674.5, 'X3': 245.0}
copy["X2"] = 808
print(orig) # {'X2': 674.5, 'X3': 245.0}
print(copy) # {'X2': 808, 'X3': 245.0}
  • 3
    This only works for simple dictionaries. Why not use `deepcopy`, which is built expressly for this purpose? – Anthony Feb 07 '20 at 23:54
  • Not the best way. Good response is bellow. – David Beauchemin May 23 '20 at 00:32
  • somehow none of the "copies" worked for me. Only this way it works. Another better way to write this would be using dictionary comprehension; like this: `def _copy_dict(dictionary:dict): return {key: dictionary[key] for key in dictionary}` – Davi A. Sampaio Apr 20 '22 at 16:14
-5

You can use directly:

dict2 = eval(repr(dict1))

where object dict2 is an independent copy of dict1, so you can modify dict2 without affecting dict1.

This works for any kind of object.

Viiik
  • 23
  • 2
  • 5
    This answer is incorrect, and should not be used. A user-defined class, for example, may not have an appropriate `__repr__` to be reconstructed by eval, nor may the object's class be in the current scope to be called. Even sticking with built-in types, this will fail if the same object is stored under multiple keys, as `dict2` would then have two separate objects. A self-referential dictionary, where `dict1` contains itself, will instead contain `Ellipsis`. It would be better to use `dict1.copy()` – Eldritch Cheese Oct 31 '17 at 17:11
  • Objects (or "values") are not expected to always have a faithful representation by character strings, not in a usual human readable way in any case. – Alexey Feb 21 '18 at 12:50
-7

Another cleaner way would be using json. see below code

>>> a = [{"name":"Onkar","Address": {"state":"MH","country":"India","innerAddress":{"city":"Pune"}}}]
>>> b = json.dumps(a)
>>> b = json.loads(b)
>>> id(a)
2334461105416
>>> id(b)
2334461105224
>>> a[0]["Address"]["innerAddress"]["city"]="Nagpur"
>>> a
[{'name': 'Onkar', 'Address': {'state': 'MH', 'country': 'India', 'innerAddress': {'city': 'Nagpur'}}}]
>>> b
[{'name': 'Onkar', 'Address': {'state': 'MH', 'country': 'India', 'innerAddress': {'city': 'Pune'}}}]
>>> id(a[0]["Address"]["innerAddress"])
2334460618376
>>> id(b[0]["Address"]["innerAddress"])
2334424569880

To create another dictionary do json.dumps() and then json.loads() on the same dictionary object. You will have separate dict object.

Onkar
  • 297
  • 5
  • 9