SlowSloth
SlowSloth

Reputation: 33

python dictionary inside/outside for loop

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

Answers (6)

laven_qa
laven_qa

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

Tai
Tai

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:

  • An object can have different names that all refer to it.
  • A variable name can refer to different objects at different moments.

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

user9158931
user9158931

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

RoadRunner
RoadRunner

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

R.A.Munna
R.A.Munna

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

sometimesiwritecode
sometimesiwritecode

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

Related Questions