[Tutor] Making Doubly Linked List with Less Lines of Code.

Alan Gauld alan.gauld at btinternet.com
Fri Jan 2 02:35:48 CET 2015


On 02/01/15 01:03, Alex Kleider wrote:

> I don't think I understand the distinction between 'copies' and 'repeats'.

copy creates a new object with the same attributes as the original

original = [1,2,3]
copy = original[:]   # slicing creates a copy

copy == original -> True
copy is original -> False

Repeats replicates the reference to the object but
does not create a new object.

reference = original   # both refer to same object

reference = original -> True
reference is original -> True

> I think I understand the difference between copy and deep copy and I
> think that is the issue here but it isn't yet clear.

Deep copy is not an issue here.

>>>> s_grid = [[0]*5 for i in range(4)]
> # So for each iteration of the list comprehension,
> # a brand new, ?immutable? object ( a list of zeros) is created.
 > # Immutable by virtue of the fact that there is no reference to it
 > # and therefore it can't be changed?????

It's not immutable. Whether a reference to it exists or not
has no bearing on whether it has the potential to be changed.

In fact each object created has a reference:
s_grid[0], s_grid[1], etc...

You have 5 objects, each a list of 5 zeros.
All 5 lists are mutable and all 5 are equal but not
identical (ie. not the same object).

>>>> s_grid
> [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
>>>> s_grid[1][1] = 99
>>>> s_grid
> [[0, 0, 0, 0, 0], [0, 99, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]  #

And as expected changing one object has no impact on the others.
And by changing it you demonstrate that the objects are not
immutable - you just mutated it!

>>>> l = [0]*5
>>>> l
> [0, 0, 0, 0, 0]

You now have one list object containing 5 zeros and
a reference to it from 'l'

>>>> grid = [l for i in range(4)]

Now you have 4 more references to the same object 'l'
refers to.

> # In this form, the list comprehension is encountering a mutable
> # object by virtue of the fact that there is a reference to it?

No, the reference is irrelevant.
It is mutable by virtue of being a list.

>>>> grid[1][1] = 99
>>>> grid
> [[0, 99, 0, 0, 0], [0, 99, 0, 0, 0], [0, 99, 0, 0, 0], [0, 99, 0, 0, 0]]

You modified the object so all references (including the original 'l') 
will reflect the change

> # Is the crux of the matter that l is mutable (because it is a reference,)

No the objects are mutable in both examples.
mutable means you can change them. It has nothing to do with
whether there is a reference or not. (Although, if there
were truly no references the object would be destyroyed
by the garbage collector)

> # while [0]*5 is not (because it is an expression?)

[0]*5 is an expression that yields a list object.
The list object is mutable. You proved that by
changing one of them.

>>>> my_grid = [[0, 0, 0, 0] for i in range(4)]
>>>> my_grid
> [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]

Now you have created another list of 5 objects. Again each object has 4 
zeros and  they are equal but not identical. They are all mutable.
They are all referenced via my_grid. (my_grid[0],...)

>>>> my_grid[1][1] = 99
>>>> my_grid
> [[0, 0, 0, 0], [0, 99, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]

Again you changed(mutated) one of the objects. The
others remain untouched.

>>>> another_grid = [[0]*5]*4

Here you create a list of 4 references to the list produced by [0]*5
One list object, 4 references.

> # The explanations above don't seem to explain things here.
>>>> another_grid
> [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
>>>> another_grid[1][1] = 99
>>>> another_grid
> [[0, 99, 0, 0, 0], [0, 99, 0, 0, 0], [0, 99, 0, 0, 0], [0, 99, 0, 0, 0]]

Again there is only one list object, so when you change it via
any of the references all the references reflect that change.

> My interpretation is that we appear to be getting a deep copy at the
> inner level of a multiplication but a not deep copy at the outer level.

No copying is going on at any point.

> List comprehension provides us with a deep copy but only if we give it a
> literal (as opposed to a reference.)

No, list comprehensions (and generator expressions in general)
return a sequence made up of whatever object the first
expression evaluates to. That could be an existing object
(like the one referenced by 'l' above) or a newly created
(possibly literal) object like [0, 0, 0, 0].

HTH
-- 
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos




More information about the Tutor mailing list