Python - List of Lists Slicing Behavior
Question: When I define a list and try to change a single item like this:

    
    
    list_of_lists = [['a', 'a', 'a'], ['a', 'a', 'a'], ['a', 'a', 'a']]
    list_of_lists[1][1] = 'b'
    for row in list_of_lists:
        print row
    

It works as intended. But when I try to use list comprehension to create the
list:

    
    
    row = ['a' for range in xrange(3)]
    list_of_lists = [row for range in xrange(3)]
    list_of_lists[1][1] = 'b'
    for row in list_of_lists:
        print row
    

It results in an entire column of items in the list being changed. Why is
this? How can I achieve the desired effect with list comprehension?


Answer: Think about if you do this:

    
    
    >>> row = ['a' for range in xrange(3)]
    >>> row2 = row
    >>> row2[0] = 'b'
    >>> row
    ['b', 'a', 'a']
    

This happens because `row` and `row2` are two different names for _the same
list_ (you have `row is row2`) - your example with nested lists only obscures
this a little.

To make them different lists, you can cause it to re-run the list-creation
code each time instead of doing a variable assignment:

    
    
    list_of_lists = [['a' for range in xrange(3)] for _ in xrange(3)]
    

or, create a new list each time by using a slice of the full old list:

    
    
    list_of_lists = [row[:] for range in xrange(3)]
    

Although this isn't guaranteed to work in general for all sequences - it just
happens that list slicing makes a new list for the slice. This doesn't happen
for, eg, numpy arrays - a slice in those is a view of part of the array rather
than a copy. If you need to work more generally than just lists, use the
`copy` module:

    
    
    from copy import copy
    list_of_lists = [copy(row) for range in xrange(3)]
    

Also, note that `range` isn't the best name for a variable, since it shadows
the builtin - for a throwaway like this, `_` is reasonably common.

