2

Let's assume that a is some reference variable and I want to put it into a list three times:

a = [1,2,3]
b = [a]*3
>>> b
[[1, 2, 3], [1, 2, 3], [1, 2, 3]]

So this still works as expected. But if I append an element to one of the reference variables it is reflected to all of them:

>>> b[0].append(4)
>>> b
[[1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4]]

Does this happen because the * operator in the first code block only copies the references and the list only points to a? Do I need a for-loop in order to be able to have a list of independent reference variables (copies) n times? (where n is 3 in the example above)

How excactly does the * operator work in this instance?

With a for-loop and the append()-Method the behaviour is the same - are references also used here?:

>>> a = [1,2,3]
>>> b = []
>>> for i in range(2):
...     b.append(a)
...
>>> b
[[1, 2, 3], [1, 2, 3]]
>>> b[0].append(4)
>>> b
[[1, 2, 3, 4], [1, 2, 3, 4]]

When inserting copies the behaviour is as expected:

>>> a = [1,2,3]
>>> b = []
>>> for i in range(2):
...     b.append(a.copy())
...
>>> b
[[1, 2, 3], [1, 2, 3]]
>>> b[0].append(4)
>>> b
[[1, 2, 3, 4], [1, 2, 3]]

Is there a shorter, more convenient way to do this than to loop with .append() and .copy() as I did above?

My Python-Version is Python 3.8.6 Note that my questions go beyond just using deep_copy() as it is about inserting elements more often in a list and the *-operator - I know what deep_copy() is!

Martin Dallinger
  • 369
  • 1
  • 12
  • 1
    See the dupes, there are about 10+ more of them already on SO. The (my) preferred way is to do `q = [a[:] for _ in range(3)]` (shallow copy, does not work for list of list of lists) or `q = [a.copy() for _ in range(3)]` (use `deepcopy()` for lists of lists of lists). The problem is for all "referencetypes - sets, dicts etc behave the same - your list contains the reference 3 times, all refs point to the same data, if you add to the data through any of the refs all refs still point to the same changed data. – Patrick Artner Apr 04 '21 at 08:41
  • 1
    @PatrickArtner preferred one most often is actually use `list(a)` which will work despite the type of the input argument – Antti Haapala -- Слава Україні Apr 04 '21 at 08:43
  • 1
    the `*` on lists triggers the `__mul__` overload wich inserts references. If you do not want to insert references you need to copy / deepcopy - how you do that is on you. Use `[:]`, use `list.copy()` use the `copy module` or use `list(yourotherlist)` - just be aware on when to deeply copy if you have nested datastructs that are also reference-based. – Patrick Artner Apr 04 '21 at 08:55

0 Answers0