I see a good answer posted, but felt some explanation is in order here since this is a common gotcha for people new, and sometimes experienced, with Python. There are two ways off the top of my head where this can happen. One is in list declarations as you have, and the other is in function/method declarations.
The line li = [[]] * 8
creates a list of references to the same list. That's why when you append to one li[0].append(10)
, the list shows you eight lists with 10 as a member. The solution would be to use a list comprehension in the declaration.
li = [[] for _ in range(8)]
.
Now for the next gotcha. Function or method declarations. Often we want default values for parameters like so:
>>> def foo(bar=[]):
... bar.append('hello')
... return bar
...
>>> foo()
['hello']
>>> foo()
['hello', 'hello']
>>> foo()
['hello', 'hello', 'hello']
>>>
The problem with using []
as a default value is the interpreter, when it parses the function declaration, creates only one list instance as the default value. So every time you call the function, that same list is getting passed in.
This goes for dictionaries as well. In fact, using any sort of mutable object instance as a parameter default value in function declarations could potentially cause confusion.
I think the key takeaway is * 8
applied to certain objects like lists creates references - not instances.