[Tutor] Making Doubly Linked List with Less Lines of Code.
Steven D'Aprano
steve at pearwood.info
Fri Jan 2 22:57:38 CET 2015
On Fri, Jan 02, 2015 at 09:57:29AM -0800, Alex Kleider wrote:
> On 2015-01-01 17:35, Alan Gauld wrote:
>
> >Repeats replicates the reference to the object but
> >does not create a new object.
>
> This part I can understand but, as Steven has pointed out,
> this behaviour changes if the object being repeated is immutable.
> Why would one get a new object (rather than a new reference to it)
> just because it is immutable? It's this difference in behaviour
> that depends on mutability that I still don't understand even though
> Steven did try to explain it to me:
> """
> If the list items are immutable, like ints or strings, the difference
> doesn't matter. You can't modify immutable objects in-place, so you
> never notice any difference between copying them or not.
> """
No, you misunderstood what I was trying to say.
Let's create a list with one mutable and one immutable object, then
double it:
py> a = [{}, 999]
py> b = a*3
py> print(b)
[{}, 999, {}, 999, {}, 999]
The list b has 6 items, but only two different objects inside b: there
is a dict, repeated three times, and an int, repeated three times. We
can check this by printing the IDs of each item:
py> print([hex(id(x)) for x in b])
['0xb7bf1aec', '0xb7b6c580', '0xb7bf1aec', '0xb7b6c580', '0xb7bf1aec', '0xb7b6c580']
If you study them carefully, you will see only two distinct IDs:
'0xb7bf1aec', '0xb7b6c580'
The exact values you get will differ, of course. On some versions of
Python, you might see something like:
['0x1', '0x2', '0x1', '0x2','0x1', '0x2']
depending on what values the compiler uses for the IDs. But the
important thing is there are only two of them. We can let Python check
for duplicates by using a set:
py> print(set([hex(id(x)) for x in b]))
{'0xb7b6c580', '0xb7bf1aec'}
Go back to our list b. Naturally, we can modify *the list* directly:
py> b[2] = {'a': 1}
py> b[3] = 23
py> print(b)
[{}, 999, {'a': 1}, 23, {}, 999]
Notice that when we assign to a list item, it replaces whatever
assignment was there: position 2 used to refer to an empty dict, now it
refers to a different dict; position 3 used to refer to an int, now it
refers to a different int. We can change the list, because lists are
mutable.
We can change dicts *in place* too:
py> b[0]['c'] = 3
py> print(b)
[{'c': 3}, 999, {'a': 1}, 23, {'c': 3}, 999]
Because we have modified the dict object, not re-assigned it, the change
shows up in both position 0 and position 4. It doesn't show up in
position 2, because it is a different dict there now.
But there is no way to change ints in place! Because they are immutable,
there's nothing we can do to change that int 999 into a different value.
It will always be 999. The only way to change an int is to replace it
with a different object, and we've seen that the way to do that in
Python is by assigning to the list index. Even something that at first
glance looks like "increment" is actually "add 1 and re-assign":
py> b[1] += 1
py> print(b)
[{'c': 3}, 1000, {'a': 1}, 23, {'c': 3}, 999]
py> print([hex(id(x)) for x in b])
['0xb7bf1aec', '0xb7b6c600', '0xb7afb70c', '0x823c160', '0xb7bf1aec', '0xb7b6c580']
Now there are five distinct IDs.
With mutable objects, identity can be important. There is a difference
between:
a = []
b = []
and
a = []
b = a
In the first case, a and b are distinct lists. In the second case, a and
b are the same list.
But with immutable objects, there is nothing you can do (except check
the IDs) that will reveal the difference between having one or two
distinct objects:
a = 123
b = 123
*may or may not* set a and b to distinct objects. Because when it comes
to immutable objects, it makes no difference.
--
Steven
More information about the Tutor
mailing list