Why the list creates in two different ways? Does it cause by the mutability of its elements? Where the Python document explains it?

Greg Ewing greg.ewing at canterbury.ac.nz
Tue Jun 15 21:00:11 EDT 2021


On 16/06/21 12:15 pm, Avi Gross wrote:
> May I ask if there are any PRACTICAL differences if multiple immutable
> tuples share the same address or not?

Only if some piece of code relies on the identity of tuples
by using 'is' or id() on them.

There's rarely any need to write code like that, though.
Normally you should compare tuples using '==', not 'is'.

Exceptions to this usually involve something like cacheing
where identity is only used for optimisation purposes,
and the end result doesn't depend in it.

> I mean if I use a tuple in a set or as the key in a dictionary and a second
> one comes along, will it result in two entries one time and only one the
> other time?

Dicts and sets compare keys by equality, not identity, so
there is no problem here.

 >>> a = 1
 >>> b = 2
 >>> t1 = (a, b)
 >>> t2 = (a, b)
 >>> t1 is t2
False
 >>> d = {}
 >>> d[t1] = 'spam'
 >>> t2 in d
True
 >>> s = set()
 >>> s.add(t1)
 >>> t2 in s
True

> Some languages I use often have a lazy evaluation where things are not even
> copied when doing some things and only copied if absolutely needed

 > So by that argument, you could have the copies of the list also be the
 > same at first and since they are mutable, they might diverge later

Python is not one of those languages, though, and it won't do things
like that. (At least not on its own -- you can certainly implement
such a lazily-copied data structure if you want.)

> Now if you really still want true copies, what ways might fool a compiler?

I've shown one way above that works in CPython, but a smarter
implementation might notice that t1 and t2 will always be equal
and merge them.

> NoDup = [(5, 2), (6-1, 6/3), (12%7, 1/1 + 1/1)]

CPython merges the last two of these, but not the first:

 >>> NoDup = [(5, 2), (6-1, 6/3), (12%7, 1/1 + 1/1)]
 >>> [id(x) for x in NoDup]
[4387029696, 4386827968, 4386827968]

The reason is that '/' does float division in Python 3. If you
use int division instead, they all get merged:

 >>> NoDup = [(5, 2), (6-1, 6//3), (12%7, 1//1 + 1//1)]
 >>> [id(x) for x in NoDup]
[4387030272, 4387030272, 4387030272]

So you need to be tricker than that to fool it!

The bottom line is, don't write code that depends on the identities
of immutable objects.

-- 
Greg


More information about the Python-list mailing list