Creating Lists of Lists Without Sharing References
Credit: David Ascher
Problem
You want to create a multidimensional list, but the apparently simplest solution is fraught with surprises.
Solution
Use list comprehensions (also known as list displays) to avoid implicit reference sharing:
multilist = [[0 for col in range(5)] for row in range(10)]
Discussion
When a newcomer to Python is shown the power of the multiplication operation on lists, he often gets quite excited about it, since it is such an elegant notation. For example:
>>> [0] * 5
[0, 0, 0, 0, 0]The problem is that one-dimensional problems often grow a second dimension, so there is a natural progression to:
>>> multi = [[0] * 5] * 3
>>> print multi
[[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]This appears to have worked, but the same newcomer is then often puzzled by bugs, which typically can be boiled down to the following test:
>>> multi[0][0] = 'Changed!'
>>> print multi
[['Changed!', 0, 0, 0, 0], ['Changed!', 0, 0, 0, 0], ['Changed!', 0, 0, 0, 0]]This problem definitely confuses most programmers at least once, if not a few times (see the FAQ entry at http://www.python.org/doc/FAQ.html#4.50). To understand it, it helps to decompose the creation of the multidimensional list into two steps:
>>> row = [0] * 5 # a list with five references to 0 >>> multi = [row] * 3 # a list with three references to the row object
The problem still exists in this version (Python is not that magical). The comments are key to understanding ...