1

The problem goes like this:

image = 'image_name'
stats = [1,2,3]
team_color = 'red'
character = [image, stats, team_color]

character[1][1] -= 1
print( character, stats )

and this returns

['image_name', [1, 1, 3], 'red'] [1, 1, 3]

The problem is that I don't want to change the list stats because I use it to create other characters so it needs to remain constant. I know of a few workarounds such as making a new list with a code like this one:

newList = []
for stat in stats:
     newList.append( stat )

character = [image,newList,team_color]

but I was wondering if there is an easier and shorter way to solve this problem.

Thanks!

bnn678
  • 55
  • 7

3 Answers3

2

Just copy the list by indexing. list[:] will copy the list, so that any change will not reflect in original one.

character = [image, stats[:], team_color]
character[1][1] -= 1

print( character, stats )
(['image_name', [1, 1, 3], 'red'], [1, 2, 3])
Vishnu Upadhyay
  • 5,043
  • 1
  • 13
  • 24
1

To make a copy of some list, you can use slice operation:

orig_list = [1, 2, 3, 4]
copy_list = orig_list[:]
print(orig_list, copy_list)  # [1, 2, 3, 4] [1, 2, 3, 4]
orig_list[0] = 42
print(orig_list, copy_list)  # [42, 2, 3, 4] [1, 2, 3, 4]
Ihor Pomaranskyy
  • 5,437
  • 34
  • 37
1

Within Python, a list is a mutable object and therefore any variables that point to that object will see any changes, no matter when it is modified.

You can see this by a simple program like this:

>>> a = [1, 2, 3]
>>> b = a
>>> b.append(4)
>>> print(a)
[1, 2, 3, 4]

As can be seen, the list referenced by a has been changed as it is one and the same list object as the list referenced by b.

Therefore, in order to create a new list that doesn't affect the original, you will need to copy the stats list at the point you create the character list. The simplest manner is to use a form of slice notation to create a new copy:

>>> a = [1, 2, 3]
>>> b = a[:]
>>> b.append(4)
>>> print(a)
[1, 2, 3]
>>> print(b)
[1, 2, 3, 4]

and so for your situation:

>>> image = 'image_name'
>>> stats = [1, 2, 3]
>>> team_colour = 'red'
>>> character = [image, stats[:], team_colour]

>>> character[1][1] -= 1
>>> print(character)
['image_name', [1, 1, 3], 'red']
>>> print(stats)
[1, 2, 3]

Alternatively, passing it to list(), or using the copy.copy() within the copy library, will also return a copy of the list, but the slice notation is probably the simplest!

Finally, something like this could also be achieved with a class, and therefore you wouldn't need to use the slice notation when you instance the character:

>>> class Character(object):
...     def __init__(self, image, stats, team_colour):
...         self.image = image
...         self.stats = stats[:]  # Without the slice you will still reference the original list here!
...         self.team_colour = team_colour

>>> image = 'image_name'
>>> stats = [1, 2, 3]
>>> team_colour = 'red'
>>> fred = Character(image, stats, team_colour)

You will then also be able to change the attributes in a more explicit way:

>>> fred.stats[1] -= 1
>>> print(fred.stats)
[1, 1, 3]
>>> print(stats)
[1, 2, 3]
J2C
  • 497
  • 4
  • 8