python why can't I clear list after appending it in a for loop without it staying cleared

Viewed 1246

for example, why can't f print out with numbers 1-10 in a list.

f = []
a = []
for i in range(10):
  a.append(i)
  f.append(a)
  a.clear()
print(f)

I understand there are other ways to do this exact program but I'm curious as to why python outputs f as a list with a bunch of empty lists: [[][][][][][][][][][]].

5 Answers

You add the same a to f multiple times, and clear it on each iteration. Since it's the same list, when you clear it, you'll see this clearing in all of f's elements. The correct way of writing this snippet is to use a new list in every iteration:

for i in range(10):
  a = []
  a.append(i)
  f.append(a)

Of course, this could be shortened considerably using a list comprehension:

f = [[i] for i in range(10)]

When you do f.append(a) you append a reference to the array a, it is the same array you add every time. So when you a.clear() you delete the content of f.

To fix your code, you can try this a.copy()

f = []
a = []
for i in range(10):
    a.append(i)
    f.append(a.copy())
    a.clear()
print(f)

But better is to use a listcomprehension like this:

f = [[i] for i in range(10)]

so when you use the a.clear() ie removing all element from the list then, list object become empty and where ever this object is used all of it's value become empty. this is why you are getting empty list of list in the final output.

what you need to go was, either use deepcopy() or redefined the list object with reference to variable a.

below code is what you are looking for for your solution

f = []
a = []
for i in range(10):
  a.append(i) # use a.extend(i) if you want output [0,1,2,3,4,5,6,7,8,9]
  f.append(a)
  a = []
print(f)
# output [[0], [1], [2], [3], [4], [5], [6], [7], [8], [9]]

Below code is a little behind the scene case why your data which is removed from list a is getting removed from f list itself.

a = []
c = []
print('a->',id(a),'c->', id(c), )
# a-> 139917172826512 c-> 139917172828432
a.append(4)
print("after appending 4 to a , id(a)" ,id(a))
#after appending 4 to a , id(a) 139917172826512
c.append(a)
print("after appending a to c, id (C)-> ", id(c))
#after appending a to c, id (C)->  139917172828432
print("id(c[0]) -> ", id(c[0]), "same as id of aa")
# id(c[0]) ->  139917172826512 same as id of aa
a.clear()
print("clear a = {}, c= {}, id(A) -> {}, id(c) -> {}, id(c[0]) -> {}".format(a,c,id(a), id(c), id(c[0])))
# clear a = [], c= [[]], id(A) -> 139917172826512, id(c) -> 139917172828432, id(c[0]) -> 139917172826512
a.append(4)
print("adding 4 again  a = {}, c= {}, id(A) -> {}, id(c) -> {}, id(c[0]) -> {}".format(a,c,id(a), id(c), id(c[0])))
#adding 4 again  a = [4], c= [[4]], id(A) -> 139917172826512, id(c) -> 139917172828432, id(c[0]) -> 139917172826512
a.pop()
print("removing last element from a  again  a = {}, c= {}, id(A) -> {}, id(c) -> {}, id(c[0]) -> {}".format(a,c,id(a), id(c), id(c[0])))
# removing last element from a  again  a = [], c= [[]], id(A) -> 139917172826512, id(c) -> 139917172828432, id(c[0]) -> 139917172826512
a.append(4)
print("adding 4 again  a = {}, c= {}, id(A) -> {}, id(c) -> {}, id(c[0]) -> {}".format(a,c,id(a), id(c), id(c[0])))
# adding 4 again  a = [4], c= [[4]], id(A) -> 139917172826512, id(c) -> 139917172828432, id(c[0]) -> 139917172826512

a = []
a.append(4)
print("changing the list object of a and intilising it again   a = {}, c= {}, id(A) -> {}, id(c) -> {}, id(c[0]) -> {}".format(a,c,id(a), id(c), id(c[0])))
# changing the list object of a and intilising it again   a = [4], c= [[4]], id(A) -> 139917172767552, id(c) -> 139917172828432, id(c[0]) -> 139917172826512

print("see how id associated with the c[0] changes")
# see how id associated with the c[0] changes

You must append a copy of a to f, because when appending with a, it will be cleared too inside f. Try this instead:

f = []
a = []
for i in range(10):
    a.append(i)
    f.append(list(a)) #amended line
    a.clear()

>>>print(f)

[[0], [1], [2], [3], [4], [5], [6], [7], [8], [9]]

The concept you're missing is copy by value versus copy by reference. When working with objects in python (in this case the list named a) you're working with references (aka pointers). When you append a to f then clear a you're referencing (pointing to) the exact same object in memory. That's why a clear of a will affect the contents of f.

To instead copy the value of a, you'll need to create a new list:

f = []
a = []
for i in range(10):
  a.append(i)
  f.append([*a])
  a.clear()
print(f)

In this case, f is getting a new instance of a list that's initialized with the same contents as a. This will result in:

[[0], [1], [2], [3], [4], [5], [6], [7], [8], [9]]

Related