Appending changed list to list

Appending the same item twice to a list makes a list with the item twice, even if the appended item itself is a list.

a = []
b = ['this is in a list']
a.append(b)
a.append(b)
print(b)

Resulting in:

[['this is in a list'], ['this is in a list']]

However if the appended list has been changed

b[0] = 'list has a bit changed'
a.append(b)
print(a)

the resulting list had three times the last appended list instead of what I expected, twice the original list followed by the changed list.

[['list has a bit changed'], ['list has a bit changed'], ['list has a bit changed']]

Could you explain why the result is as above given? Thanks!

There is no “original list” and “changed list”. There is one list, which you identify as b and then append to a three times. It’s always the same list, no matter what you do with it. So when you change what’s in b[0], you’re changing that list, that one single list that you see three times in the output.

Appending doesn’t make a copy of the list, it uses the same list object. So if you append b three times, and then print, you will see b three times.

Another way of looking at this is that you now have a single list object with four names: b, a[0], a[1] and a[2]. Not four lists, there is only one list but with four different ways to refer to it.

That’s like there are many different ways people can refer to me:

  • Steve
  • Steven
  • “Mr D…”
  • stevend@some_email_address
  • “Hey you over there!”

but if Steve gets a tattoo so does Mr D because they’re the same person.

If you want to take a snapshot of b so that it becomes independent of future changes, you need to make a copy. You can copy the list (at least) four ways:

a = []
b = ['initial value']
a.append(b)  # Uses the actual b list.
a.append(b.copy())  # Make a copy.
a.append(b[:])  # Use slicing to make a copy.
import copy
a.append(copy.copy(b))  # Use the copy module.
a.append(copy.deepcopy(b))  # Make copies of the contents of b as well as b.

Slicing is probably the fastest.

Now the a list contains:

  • The b list itself; changes to b will be visible in a[0].
  • Plus four independent copies.
1 Like

Thank you so much, I now understand why things did go wrong. Thanks for the solution!

1 Like

Thank you so much, I now understand why things did go wrong.

1 Like

I am having a related problem. I want to produce a list of variants of the original list, where the first element is replaced with different digits.

The intended content of the variants list would be

[[1, 0], [0, 0]]
[[2, 0], [0, 0]]
[[3, 0], [0, 0]]
[[4, 0], [0, 0]]

However, I am getting four copies of the last variant, even though I am appending a copy of the original list as suggested in the comments here.

image

The .copy method is returning a ‘shallow’ copy; it’s copying the list, but not it’s not copying each element of the list.

For a ‘deep’ copy, use the deepcopy function of the copy module:

from copy import deepcopy

# Other lines...
    variants.append(deepcopy(original_list))

Incidentally, it’s better to post text, properly formatted, rather than a picture. Some people rely on screen readers, and it’s not fun having to re-type code from a picture.

OK, thanks. It was confusing because the simple copy() worked for one-dimensional arrays.

The screenshot preserves the nice code formatting for readability, but I will avoid posting screenshots in the future,

To preserve its formatting, select the code or traceback and then click the </> button.