Darkshadows
Darkshadows

Reputation: 51

Unexpected list append

import random
stats = []
statslist = []
rollslist = []
for var1 in range(4):
    stats.append(random.randrange(1, 7))
rollslist.append(stats)
print(stats)
b = min(stats)
stats.remove(b)
print(sum(stats))
statslist.append(sum(stats))
print(stats)
print(rollslist)
print(statslist)

actual result

[5, 1, 1, 3]
9
[5, 1, 3]
[[5, 1, 3]]
[9]

expected result

[5, 1, 1, 3]
9
[5, 1, 3]
[[5, 1, 1, 3]]
[9]

I'm expecting it to print four numbers for the fourth result instead of the three it's giving me. I appended the list before the number was removed. What am I missing?

Upvotes: 1

Views: 77

Answers (3)

bterwijn
bterwijn

Reputation: 191

You can use package memory_graph to see what data is shared:

import memory_graph as mg # see link above for install instructions
import random
random.seed(0) # use same random number each run, more clear

stats = []
statslist = []
rollslist = []
for var1 in range(4):
    stats.append(random.randrange(1, 7))
rollslist.append(stats)
print(stats)
b = min(stats)
stats.remove(b)
print(sum(stats))
statslist.append(sum(stats))
print(stats)
print(rollslist)
print(statslist)

mg.show(locals()) # show graph of a local variables

resulting in:

result1

As suggested, if you make a copy of 'stats':

import memory_graph as mg
import random
random.seed(0)

stats = []
statslist = []
rollslist = []
for var1 in range(4):
    stats.append(random.randrange(1, 7))
rollslist.append(stats.copy()) # make a copy, or use stats[:], list(stats)
print(stats)
b = min(stats)
stats.remove(b)
print(sum(stats))
statslist.append(sum(stats))
print(stats)
print(rollslist)
print(statslist)

mg.show(locals())

then stats and rollslist are independent and you get the expected result:

result2

Full disclosure: I am the developer of memory_graph.

Upvotes: 0

Mark Ransom
Mark Ransom

Reputation: 308121

You added a mutable list. When you modified it later, the modification affected the object you placed in the list, because it was a direct reference and not a copy.

The easiest way to make a copy of a list is to use slicing:

rollslist.append(stats[:])

Upvotes: 6

Huey
Huey

Reputation: 5220

as Avinash mentioned, it's because you're still referring to the stats list. Meaning, changes made later (like the removal of an item) will still be reflected. For the expected behaviour, you can make a copy of the list like so:

newCopy = list(stats)
rollslist.append(newCopy)

Upvotes: 3

Related Questions