String by value; Dictionary by reference?

Tags: , ,



I’m coming from C, learning Python. In Python (3.5.2), it seems that assignment of one data type to another of the same type is sometimes done by value and sometimes by reference.

For example, strings are assigned by value:

>>> str1 = "hello"
>>> str2 = str1
>>> print(str1, str2)
hello hello
>>> str2 = "goodbye"
>>> print(str1, str2)
hello goodbye

This is the behavior I expect. However, it works differently with dictionaries:

>>> dict1 = {'key1':'val1', 'key2':'val2'}
>>> dict2 = dict1
>>> print(dict1, dict2)
{'key2': 'val2', 'key1': 'val1'} {'key2': 'val2', 'key1': 'val1'}
>>> dict2['key1'] = 'newval'
>>> print(dict1, dict2)
{'key2': 'val2', 'key1': 'newval'} {'key2': 'val2', 'key1': 'newval'}

Notice that both dict1 and dict2 were changed. Similarly, if I add a key/value pair to either of the dictionaries it will appear in both. Argh!

(sorry, that was my C-background speaking) :)

How am I to know which behavior to expect for any given variable type? Is there a method to this madness or will I simply need to remember arbitrary rules?

P.S. I realize I can get my expected behavior by using dict2 = dict(dict1).


The “possible duplicate” contains good info on how to do it, but I’m interested in why I have to. The answers to this question are already very helpful!

Answer

In Python, everything is by reference; This is different from C, variable is not a box. The assignment is actually a binding.

str1 = "hello"
str2 = str1

Both str1 and str2 reference to “hello”, but string in Python is immutable, so modifying str2, would creating a new binding, and hence do not affect the value of str1

str2 = "hack"
# here str1 will still reference to "hello" object

Dict works the same:

d1 = {"name": "Tom"}
d2 = d1

d2 and d1 will reference the same object. If change d2 to a new value do not affect the value of d1; But instead, if we only modify d2 in place, like d2['age'] = 20, the value of d1 would be changed since they share the same object.

d2 = {"name": "Hack"}
# the value of d1 does not change

Luciano Ramalho summarized it in Fluent Python, Chapter 8, Variables Are Not Boxes section

To understand an assignment in Python, always read the righthand side first: that’s where the object is created or retrieved. After that, the variable on the left is bound to the object, like a label stuck to it. Just forget about the boxes.



Source: stackoverflow