Reputation: 160
I'm new to python and am just learning about immutable and mutable objects (I've never came across this before with my limited coding experience in MATLAB and C#).
I wanted to know why, if dicts in python are mutable, does editing a dict contained in a second dict not change the second dict?
Here is an example, where a dict (batman) is added to a dict of superhero names (super_hero_names). When batman is later changed, it isn't reflected in the superhero names dict. This makes sense to me if dicts were immutable like strings, but they are mutable so why is this happening?
super_hero_names = {
'Superman' : 'Clark Kent',
'Spiderman' : 'Peter Parker'
}
batman = {'Batman' : 'Bruce'}
super_hero_names.update(batman)
batman['Batman'] = 'Bruce Wayne' # (edited)
print(super_hero_names)
# Output: {'Superman': 'Clark Kent', 'Spiderman': 'Peter Parker', 'Batman': 'Bruce'}
Upvotes: 5
Views: 18080
Reputation: 54313
The problem in your code is that strings are immutable: you cannot modify the string 'Bruce'
into 'Bruce Wayne'
. You replace it and the reference is gone. If you use a mutable object as value, you can achieve the desired result:
class Person:
def __init__(self, name):
self.name = name
def __repr__(self):
return repr(self.name)
super_hero_names = {
'Superman': Person('Clark Kent'),
'Spiderman': Person('Peter Parker')
}
bruce = Person('Bruce')
batman = {'Batman': bruce}
super_hero_names.update(batman)
bruce.name = 'Bruce Wayne'
print(super_hero_names)
# {'Superman': 'Clark Kent', 'Spiderman': 'Peter Parker', 'Batman': 'Bruce Wayne'}
Ruby and Python often have a very similar syntax. Ruby strings are mutable, so your code would work in Ruby with very few modifications:
super_hero_names = {
'Superman' => 'Clark Kent',
'Spiderman' => 'Peter Parker'
}
batman = {'Batman' => 'Bruce'}
super_hero_names.update(batman)
batman['Batman'] << ' Wayne' # Mutates the string, doesn't replace it!
print(super_hero_names)
# {"Superman"=>"Clark Kent", "Spiderman"=>"Peter Parker", "Batman"=>"Bruce Wayne"}
Upvotes: 8
Reputation: 895
In this case, update()
behaves like this:
for key, value in batman.items():
super_hero_names[key] = value
Here, super_hero_names.update(batman)
first checks whether super_hero_names
has 'Batman' key. If exist, it overwrite (or update) the value. If not, it create 'Batman' and just assign the value to the key.
Added:
Here is a sample code. Instead of using dictionary as a data container, I used list to hold multiple superman dictionaries. As you said, dictionary is mutable, so update method modifies the contents in the list of super_hero_names
.
superman = {'Superman' : 'Clark Kent'}
spiderman = {'Spiderman' : 'Peter Parker'}
super_hero_names = [
superman,
spiderman
]
batman = {'Batman' : 'Bruce'}
super_hero_names.append(batman)
print(super_hero_names)
# [{'Superman': 'Clark Kent'}, {'Spiderman': 'Peter Parker'}, {'Batman': 'Bruce'}]
batman.update({'Batman': 'test'})
print(super_hero_names)
# [{'Superman': 'Clark Kent'}, {'Spiderman': 'Peter Parker'}, {'Batman': 'test'}]
Upvotes: 0
Reputation: 55509
You could achieve what you want by storing the names in lists, but it makes the code more cluttered and less efficient, due to the extra layer of indirection.
super_hero_names = {
'Superman' : ['Clark Kent'],
'Spiderman' : ['Peter Parker'],
}
batman = {'Batman' : ['Bruce']}
super_hero_names.update(batman)
batman['Batman'][0] = 'Bruce Wayne'
print(super_hero_names)
output
{'Superman': ['Clark Kent'], 'Spiderman': ['Peter Parker'], 'Batman': ['Bruce Wayne']}
We could also do that update using
batman['Batman'][0] += ' Wayne'
Upvotes: 1
Reputation: 778
I hope this explains your question. When you update a dictionary it updates dictionary with the values of another dictionary, It is merging. But when you insert one dictionary into other mutability exists
super_hero_names = {
'Superman' : 'Clark Kent',
'Spiderman' : 'Peter Parker'
}
batman = {'Batman' : 'Bruce'}
super_hero_names['new'] = batman
print(super_hero_names)
batman['Batman'] = 'Bruce Wayne'
print(super_hero_names)
batman = {'Batman' : 'Bruce Wayne'}
print(super_hero_names)
{'Spiderman': 'Peter Parker', 'new': {'Batman': 'Bruce'}, 'Superman': 'Clark Kent'}
{'Spiderman': 'Peter Parker', 'new': {'Batman': 'Bruce Wayne'}, 'Superman': 'Clark Kent'}
{'Spiderman': 'Peter Parker', 'new': {'Batman': 'Bruce Wayne'}, 'Superman': 'Clark Kent'}
Upvotes: 0
Reputation: 356
Each time you create the dictionary batman
, you are actually creating a dictionary and assigning it to the variable batman
I believe what you are trying to do is this:
super_hero_names = {
'Superman' : 'Clark Kent',
'Spiderman' : 'Peter Parker'}
batman = {'Batman' : 'Bruce'}
super_hero_names.update(batman)
super_hero_names['Batman'] = 'Bruce Wayne'
print(super_hero_names)
The output in this case will be:
{'Superman': 'Clark Kent', 'Spiderman': 'Peter Parker', 'Batman': 'Bruce Wayne'}
Upvotes: 0