0

I'm using Python 2.7.12.

I'm having a problem that I think is best explained through example. Why does the .append() behaviour of c differ from a and b?

#Three different but equivalent methods to construct empty list:

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

b = [[] for _ in range(10)]

c = [[]]*10

print a
print b
print c

#Check to make sure they're equivalent. They are.
print a==b
print b==c
print a==c

#Carry out the same operation on all lists
a[1].append(6)
b[1].append(6)
c[1].append(6)

#Woah!  c is now different than a and b!
print a
print b
print c

print a==b
print b==c
print a==c

OUTPUT:

[[], [], [], [], [], [], [], [], [], []]
[[], [], [], [], [], [], [], [], [], []]
[[], [], [], [], [], [], [], [], [], []]
True
True
True
[[], [6], [], [], [], [], [], [], [], []]
[[], [6], [], [], [], [], [], [], [], []]
[[6], [6], [6], [6], [6], [6], [6], [6], [6], [6]]
True
False
False
  • I think that in `a` & `b` it is creating a list with 10 different empty lists. Whereas, `c` is a list of the same 10 lists. So if you change the first list in `c` all the others are also changed. – Matt Sep 28 '16 at 00:19
  • 1
    Similar question was answered here: http://stackoverflow.com/questions/240178/python-list-of-lists-changes-reflected-across-sublists-unexpectedly – Matt Sep 28 '16 at 00:22
  • Another dupe: http://stackoverflow.com/q/240178/748858 – mgilson Sep 28 '16 at 00:23
  • Common Python gotcha: `[[]]*10` creates 10 references to the same empty list. Consider `li=[1]; li2=[li]*10; li2[0][0]=22` Try that... – dawg Sep 28 '16 at 00:25
  • @mgilson: Your dup is better. Can close as dupe with that reference? – dawg Sep 28 '16 at 00:26

3 Answers3

0

Because of the way you've created c, all the lists are the same. Therefore appending to one will append to the rest.

user3543300
  • 499
  • 2
  • 9
  • 27
0

A friend of mine just enlightened me and I'll post it here in case it helps others.

c=[[]]*10

builds a list of lists that all point to the same memory location, and thus all elements will always be identical. As a demonstration, setting the first element of the first sub-list to 10,

c[0][0]=10
print c

produces

[[10], [10], [10], [10], [10], [10], [10], [10], [10], [10]]

Comments on why this behaves as it does would be well received.

  • To answer the _why_, consider `lst = [[a, b, c]]; lst2 = lst * 2`. Spread out across 2 lines, it becomes easier to see that there isn't really any reason that multiplying a list _should create new_ instances. Indeed, I haven't even specified what `a`, `b` and `c` _are_. Creating a (deep) copy of them could be expensive and (AFAIK) python never deep copies something unless you ask for it to explicitly. – mgilson Sep 28 '16 at 00:31
  • Perfect, this is very clear! –  Sep 28 '16 at 00:33
0

This creates a list of 10 independent empty lists:

b = [[] for _ in range(10)]

This creates a list of 10 copies of the same empty list:

c = [[]]*10

In other words, c[0] and c[1], etc., all refer to the same empty list. Changing c[0] is the same thing as changing c[1].

Example

In Cpython, there is a function id to determine the identity of an object. First, let's create b:

>>> b = [[] for _ in range(10)]
>>> id(b[0]) == id(b[1])
False

As you can see, b[0] and b[1] are different objects.

Now, let's create c:

>>> c = [[]]*10
>>> id(c[0]) == id(c[1])
True

By contrast, c[0] and c[]1] refer to the same (mutable) object. Thus, modifying the list referred to by c[0] modifies them all:

>>> c[0].append(6)
>>> c
[[6], [6], [6], [6], [6], [6], [6], [6], [6], [6]]

Instead of modifying a mutable object, it is possible, to make c[0] refer to a different object:

>>> c[0] = 'new'
>>> c
['new', [6], [6], [6], [6], [6], [6], [6], [6], [6]]
John1024
  • 109,961
  • 14
  • 137
  • 171