简体   繁体   中英

Does dictionary assignment results in pointing to the same object in Python?

While implementing some design patterns in Python, I found something interesting about Dictionaries that seems unusual. I created a variable dict1 with dict constructor. Then dict1 was assigned to dict2 . But while changing a value of a key in dict2 , it affected dict1 .

Code:

dict1 = dict(a=1, b=2)
dict2 = dict1
print("dict1 = ", dict1)
print("dict2 = ", dict2)

# assigning value of key 'a' in dict2 only
dict2['a'] = 0
print("---------------------------")
print("dict1 = ", dict1)
print("dict2 = ", dict2)

Output:

dict1 =  {'b': 2, 'a': 1}
dict2 =  {'b': 2, 'a': 1}
---------------------------
dict1 =  {'b': 2, 'a': 0}
dict2 =  {'b': 2, 'a': 0}

I found the same type of behavior for Lists also:

list1 = [1, 2, 3]
list2 = list1
print(list1, list2)
print("---------------------------")
list2.append(4)
print(list1, list2)

Output:

[1, 2, 3] [1, 2, 3]
---------------------------
[1, 2, 3, 4] [1, 2, 3, 4]

But not in strings:

str1 = "Good"
str2 = str1
print(str1, ",", str2)
print("---------------------------")
str2+=" thing"
print(str1, ",", str2)

Output:

Good , Good
---------------------------
Good , Good thing

It is obvious that dictionary & list assignment differs from string assignment. But how does it work? I was looking for some explanation or related resources. Can anyone help me out ? Thanks in advance.

  1. Python knows names and values.
  2. When you do x = something , x is a new name for the value of something .
  3. Assignment never copies data.

With that in mind, let's go over the two examples:

When you do

dict2 = dict1

dict2 is a new name for the dictionary {'a':1, 'b':2} which also has the name dict1 . All changes to the dictionary will be visible across all names!

When you do

str2 += " thing"

you are rebinding the name str2 to the result of str2 + " thing" . You are building an entirely new string, and rebind the name str2 . str1 and str2 are now names for different strings and str1 is still pointing to the original string.

One last thing/pitfall to keep in mind: sometimes, the += operator can trick you and x += y will do something else than x = x + y .

Here's an example:

>>> x = [1, 2, 3]
>>> y = x
>>> x = x + [4, 5, 6]
>>> x
[1, 2, 3, 4, 5, 6]
>>> y
[1, 2, 3]

As expected, when you do x = x + [4, 5, 6] , you build a new list and rebind the name x . y is still pointing to the old list. However...

>>> x = [1, 2, 3]
>>> y = x
>>> x += [4, 5, 6]
>>> x
[1, 2, 3, 4, 5, 6]
>>> y
[1, 2, 3, 4, 5, 6]

This is unexpected, since conceptually

x += [4, 5, 6] 

should do the same as

x = x + [4, 5, 6]

What happens is that when you use += you are calling __iadd__ on x , ie what happens is x.__iadd__([4, 5, 6]) .

In the case of lists, __iadd__ extends the list in place instead of building a new list object, so x += [4, 5, 6] was equivalent to

x.extend([4, 5, 6]) 

and then returning x . Strings behave as expected when using += , ie a new string is built and you reassign the name.

The answer to the question posed in the title is "yes". But this is not specific to dicts and lists - it is exactly the same for any object.

Neither is it true that assignment differs from strings. The only difference is that dicts and lists allow you to mutate them; you can see that your code does different things in each case - append for a list and key assignment for a dict, but += for a string. These are different operations, so it shouldn't surprise you that they have different behaviours.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM