Reputation: 33
I would like to change one of my elements in the dictionary but if I were to put new_alien
outside the loop, all the elements in the dictionary gets changed. Why is that?
#ALL aliens get changed when I put put the dictionary up here
new_alien = {'colour': 'green'}
aliens=[]
for alien_number in range(3):
#if i put new_alien here only one alien dictionary gets changed in the for loop (correct code)
#new_alien = {'colour': 'green'}
aliens.append(new_alien)
print(aliens)
for alien in aliens[0:1]:
if (alien['colour'] == 'green'):
alien['colour'] = 'yellow'
print(aliens[0:2])
Output if new_alien
is outside the loop:
[{'colour': 'green'}, {'colour': 'green'}, {'colour': 'green'}]
[{'colour': 'yellow'}, {'colour': 'yellow'}]
Output if new_alien
is inside the loop:
[{'colour': 'green'}, {'colour': 'green'}, {'colour': 'green'}]
[{'colour': 'yellow'}, {'colour': 'green'}]
Notice how outside the loop ALL alien dictionary:colour gets changed to yellow. Any explanation would be appreciated. Thanks!
Upvotes: 3
Views: 1797
Reputation: 176
Python Tutor is an online app that shows you what happens. You can paste your code in it and see how python interpreter runs the code.
Here is the explanation in plain text.
The following statement creates a new dict object, and the new_alien is just a reference of the dict object.
new_alien = {'colour': 'green', 'points': 5, 'speed': 'slow'}
If you put the this statement outside the loop, all elements in the list refer to the same dict object (or the same memory space) as you don't create new one for each element.
Upvotes: 1
Reputation: 7994
If you put it outside, you are appending the same new_alien
object to the aliens
dictionary. If you put it inside, you are creating 3 different new_alien
objects and then appending it to aliens
.
for loop (correct code)
new_alien = {'colour': 'green'}<-create a new dictionary {"c": "g"} and put it
under the name new_alien
aliens.append(new_alien) # add the new dictionary
Although they are all adding the same variable new_alien
, what is binding to new_alien
are different during each round of the loop. Everytime you have an assignment statement for new_alien
, like new_alien = {'colour': 'green'}
, you are (re)binding new_alien
to a newly created dictionary. Thus, when later on you change one in aliens
, it won't affect others.
While on the other case: new_alien = {'colour': 'green'}
is outside the loop, the same object reference is inserted into the dictionary for 3 times. While you changed one of it to "yellow"
, you do only change one. (There is in fact only one that you can change even though it looks there are 3 of it.) However, while you are printing it, you are also printing the same dictionary stored for 3 times! This is why it gives you the same result.
Takeaways:
In the first case, new_alien
refers to different dictionary object while the loop is executed at each step.
In the latter case, new_alien
is outside the loop, we can see that aliens[0]
, aliens[1]
, and aliens[2]
all refer to the same dictionary object. You change one of them, yes, only one object is changed. You change two of them; still, one same dictionary is changed. You read all of the three; you are just reading the same dictionary three times.
Upvotes: 1
Reputation:
That's called shallow copy , When you append that item you are actually appending same object and when you modify anything to it , it will affect the main object :
Solution :
You [co/sho]uld use deepcopy :
from copy import deepcopy
#ALL aliens get changed when I put put the dictionary up here
new_alien = {'colour': 'green'}
aliens=[]
for alien_number in range(3):
#if i put new_alien here only one alien dictionary gets changed in the for loop (correct code)
#new_alien = {'colour': 'green'}
aliens.append(deepcopy(new_alien))
for alien in aliens[0:1]:
if (alien['colour'] == 'green'):
alien['colour'] = 'yellow'
print(aliens[0:2])
print(new_alien)
output:
{'colour': 'green'}
[{'colour': 'yellow'}, {'colour': 'green'}]
{'colour': 'green'}
Upvotes: 0
Reputation: 26315
If you put new_alien
on the outside, you are appending the same object over and over again. You can print out the objects identity with id()
to see what I mean here:
new_alien
inside the loop:
for alien_number in range(3):
new_alien = {'colour': 'green', 'points': 5, 'speed': 'slow'}
print(id(new_alien))
aliens.append(new_alien)
Which outputs different object identities:
1577811864456
1577811864528
1577811864960
Therefore you are appending a different object every time. Different references to new_alien
, 3 separate objects. If you change one object, only one object gets changed here. This is the correct way to do this.
new_alien
outside the loop:
new_alien = {'colour': 'green', 'points': 5, 'speed': 'slow'}
for alien_number in range(3):
print(id(new_alien))
aliens.append(new_alien)
You get the same identities:
2763267730312
2763267730312
2763267730312
Which means you are appending the same object over and over again. This means that if you change one object, all of the objects will change. This is because they are all references to one object. Not the way to go if you want to modify them in the future.
Upvotes: 1
Reputation: 1709
case 1: So, when you append
new_alien = {'colour': 'green', 'points': 5, 'speed': 'slow'}
into the list, it refers the same object
of the memory. You can check memory reference by id(Your_Object_Name)
. Basically it works like a global variable.
case 2: when you try to append
it from declaring inside of the loop it creates the different object with different memory reference.
Upvotes: 1
Reputation: 3213
An object in python is viewed as an address in memory under the hood. A variable name for an object is thus just a reference to the place in the computer's memory where that object is stored. If you run this line of code:
new_alien = {'colour': 'green', 'points': 5, 'speed': 'slow'}
this creates an object in memory that can be referenced by the new_alien variable. If this line is outside of the loop it is run ONCE while if it is inside the loop it is run multiple times. When this line is run multiple times it means multiple objects are created in memory, but when it is run once only one object is created in memory and that is why they are all updated when it is declared on the outside; because they are all referencing the same memory location under the hood.
Upvotes: 0