0

Sorry if this question has been posted before, but I've had trouble finding an answer to this.
When dictionaries are instantiated as follows:

foo = bar = {'a': 0}

or

foo = {'a':0}
bar = foo

Updating one dictionary affects the other:

foo['a'] += 1
print(foo)
// {'a': 1}
print(bar)
// {'a': 1}

Yet when they are instantiated separately:

foo = {'a':0}
bar = {'a':0}

foo['a'] += 1
print(foo)
// {'a':1}
print(bar)
// {'a':0}

However, when variables are instantiated in a similar way:

foo = bar = 0
foo += 1
print(foo)
// 1
print(bar)
// 0

Firstly, what's going on here? Are the variables being set equal to the same dictionary object?
Secondly, how can I copy a dictionary to another variable and update that second variable without affecting the first? For example, I'm trying to append similar dictionaries to a list, but with one key value changed:

dic = {"foo":0,"bar":1}
list1 = [1,2,3,4]
list2 = []
for num in list1:
     temp = dic
     temp["bar"] = num
     list2.append(temp)
print(list2)
// [{"foo":0,"bar":4},{"foo":0,"bar":4},{"foo":0,"bar":4},{"foo":0,"bar":4}]

In this example, it's fairly easy to instead do the following:

list1 = [1,2,3,4]
list2 = []
for num in list1:
     list2.append({'foo':0,'bar':num})
print(list2)
// [{"foo":0,"bar":1},{"foo":0,"bar":2},{"foo":0,"bar":3},{"foo":0,"bar":4}]

but for a dictionary with many keys, is there a way to do this without hardcoding a new dictionary?

Thank you!

t.yould
  • 11
  • 3
  • 2
    `foo` and `bar` are names. They aren't dictionaries. They are both names for the same dictionary object. – Peter Wood May 18 '20 at 18:08
  • 1
    both of your variables reference the _same object_ in memory when you do `a = b = dict()`. if you want to copy something use `copy` from the standard library – gold_cy May 18 '20 at 18:08
  • the equality operator in python basically creates a link to the other item instead of copying the values – bherbruck May 18 '20 at 18:08
  • 2
    `a=b=any_object` means `a` and `b` reference to the same object `any_object` – Ch3steR May 18 '20 at 18:08
  • you must read about 'deepcopy' – Sowjanya R Bhat May 18 '20 at 18:09
  • 1
    Does this answer your question? [Does python copy objects on assignment?](https://stackoverflow.com/questions/27812789/does-python-copy-objects-on-assignment) – Mark Reed May 18 '20 at 18:09
  • [Facts and myths about Python names and values](https://nedbatchelder.com/text/names.html) – wwii May 18 '20 at 19:14

1 Answers1

4

That is because when you assign mutable variables (like variables containing dict, list, etc.) to another variable (or you pass it to a function), it passes by reference, not pass by value. That means the variable stores a reference to the object, not the actual value. On the other hand, constants like int, str, float, etc. are passed by value. That means that a copy of them is made. If you want to pass a mutable item by value, you will need to copy it with copy.deepcopy like this:

import copy
my_dict = {"a": 1, "b": 2}
my_copy_dict = copy.deepcopy(my_dict)

Now when you change my_dict to my_copy_dict they both won't be in sync.

xilpex
  • 3,097
  • 2
  • 14
  • 45
  • 1
    Your 'constants' are still passed (and assigned) by reference. The key difference is that they aren't mutable. – hpaulj May 18 '20 at 18:27