# List.copy() bug when using list of lists (Solved)

**URL:** <https://discuss.python.org/t/list-copy-bug-when-using-list-of-lists-solved/21705>\
**Category:** Python Help\
**Created:** [December 6, 2022, 7:37am UTC](https://discuss.python.org/t/list-copy-bug-when-using-list-of-lists-solved/21705 "2022-12-06T07:37:38Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![rodwa](https://avatars.discourse-cdn.com/v4/letter/r/d9b06d/32.png) [@rodwa](https://discuss.python.org/u/rodwa)\
**Post date:** [December 6, 2022, 7:37am UTC](https://discuss.python.org/t/list-copy-bug-when-using-list-of-lists-solved/21705/1 "2022-12-06T07:37:38Z")

</div>

I’m new to Python and was driven crazy by this “feature” or bug.

Run the program below and could someone please explain the behaviour.

If you read the documentation for copy() it clearly states a shadow copy of a list is created and returned. I am using 3.11.0 and IDLE and for a list of simple elements copy() works as expected.

Hoever copy() does not work as expected with a list of lists. Instead copy() returns a reference to the original list.

```auto
print("Code that demonstrates how copy() works with a simple list of elements")
eTestList = [1,2,3,4]

print("Test case: ",eTestList)
print()
print("Create and modify a copy of the list")
NeweList = eTestList.copy()
# now change the new list and print the original and new list
NeweList[0]=0
print(" Original: ",eTestList)
print(" New : ",NeweList)
print("Worked as expected. Nothing crazy here")
print()

print()
print("Code that demonstrates how copy() does not work with list of lists")
lolTestList = [[1,0,0,0]] 
lolTestList.append([2,0,0,0])
lolTestList.append([3,0,0,0])

print("Test case: ",lolTestList)
print()
print("Create and modify a copy of the list")
NewlolList = lolTestList.copy()
# now change the new list and print the original and new list
NewlolList[1][0] = 0
print(" Original: ",lolTestList)
print(" New : ",NewlolList)
print("Both lists are changed. Bad, very bad!!")
print("I think it should either work or fail but instead it appears copy() returns a reference to the original list")

```

---

<div class="post-metadata">

**Author:** ![eryksun](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/eryksun/32/697_2.png) [@eryksun](https://discuss.python.org/u/eryksun)\
**Post date:** [December 6, 2022, 8:13am UTC](https://discuss.python.org/t/list-copy-bug-when-using-list-of-lists-solved/21705/2 "2022-12-06T08:13:20Z")

</div>

The `copy()` method does a shallow copy. Use [`copy.deepcopy()`](https://docs.python.org/3/library/copy.html) to recursively copy a container object such as a list.

---

<div class="post-metadata">

**Author:** ![rodwa](https://avatars.discourse-cdn.com/v4/letter/r/d9b06d/32.png) [@rodwa](https://discuss.python.org/u/rodwa)\
**Post date:** [December 6, 2022, 8:52am UTC](https://discuss.python.org/t/list-copy-bug-when-using-list-of-lists-solved/21705/3 "2022-12-06T08:52:37Z")

</div>

Thanks for feedback

A huge trap for young players.  
If I wanted a reference I would simply assign NewList = OriginalList

To be clear  
Solution is to import the copy module

import copy  
and use copy.deepcopy(OriginalList)

By default things should work straight from the box. Why have holes for coders to fall into  
copy.

In my reality I would make copy() a deepcopy() and if you have a large dataset and want a shallow copy do something else !!!

---

<div class="post-metadata">

**Author:** ![abessman](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/abessman/32/8367_2.png) [@abessman](https://discuss.python.org/u/abessman)\
**Post date:** [December 6, 2022, 9:16am UTC](https://discuss.python.org/t/list-copy-bug-when-using-list-of-lists-solved/21705/4 "2022-12-06T09:16:24Z")

</div>

A little demonstration:

Simple reference:

```python
>>> a = [[1], [2]]
>>> b = a
>>> a is b
True
>>> # a and b are the same object, so any changes made to the contents of one affect both.
>>> b[0] = 0
>>> assert a[0] == 0

```

Shallow copy:

```python
>>> a = [[1], [2]]
>>> b = a.copy()
>>> a is b
False
>>> # a and b are different objects.
>>> b[0] = 5
>>> assert a[0] == 5
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError
>>> b = a.copy()
>>> a[0] is b[0]
True
>>> # But a[0] and b[0] are still the same object.
>>> b[0][0] = 5
>>> assert a[0][0] == 5

```

Deep copy:

```python
>>> from copy import deepcopy
>>> b = deepcopy(a)
>>> a[0] is b[0]
False
>>> # a[0] and b[0] are no longer the same object.
>>> b[0][0] = 5
>>> assert a[0][0] == 5
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError

```

> [@rodwa](#):
>
> A huge trap for young players.

Yep, I think every python developer gets bit by this at some point. Another one you’re likely to run into sooner or later is [late binding closures](https://docs.python-guide.org/writing/gotchas/#late-binding-closures):

```python
>>> funcs = [lambda: print(i) for i in range(2)]
>>> for f in funcs:
>>> f()

```

What do you think the output will be?

```auto
2
2
2

```
