[Python-Dev] "is", "==", and sameness

Gordon McMillan gmcm@hypernet.com
Fri, 12 May 2000 18:05:46 -0400


Greg Weeks wrote:

> >From the Python Reference Manual [emphasis added]:
> 
>     Types affect almost all aspects of object behavior. Even the
>     importance of object IDENTITY is affected in some sense: for
>     immutable types, operations that compute new values may
>     actually return a reference to any existing object with the
>     same type and value, while for mutable objects this is not
>     allowed.
> 
> This seems to be saying that two immutable objects are (in some
> sense) the same iff they have the same type and value, while two
> mutable objects are the same iff they have the same id().  I
> heartily agree, and I think that this notion of sameness is the
> single most useful variant of the "equals" relation.

Notice the "may" in the reference text.

>>> 88 + 11 is 98 + 1
1
>>> 100 + 3 is 101 + 2
0
>>>

Python goes to the effort of keeping singleton instances of the 
integers less than 100. In certain situations, a similar effort is 
invested in strings. But it is by no means the general case, 
and (unless you've got a solution) it would be expensive to 
make it so.
 
> Indeed, I think it worthwhile to consider modifying the "is"
> operator to compute this notion of sameness.  (This would break
> only exceedingly strange user code.)  "is" would then be the
> natural comparator of dictionary keys, which could then be any
> object.

The implications don't follow. The restriction that dictionary 
keys be immutable is not because of the comparison method. 
It's the principle of "least surprise". Use a mutable object as a 
dict key. Now mutate the object. Now the key / value pair in 
the dictionary is inaccessible. That is, there is some pair (k,v) 
in dict.items() where dict[k] does not yield v.
 
> The usefulness of this idea is limited by the absence of
> user-definable immutable instances.  It might be nice to be able
> to declare a class -- eg, Point -- to be have immutable
> instances.  This declaration would promise that:
> 
> 1.  When the expression Point(3.0,4.0) is evaluated, its
> reference count
>     will be zero.

That's a big change from the way Python works:

>>> sys.getrefcount(None)
167
>>>
 
> 2.  After Point(3.0,4.0) is evaluated, its attributes will not be
> changed.

You can make an instance effectively immutable (by messing 
with __setattr__). You can override __hash__ to return 
something suitable (eg, hash(id(self))), and then use an 
instance as a dict key. You don't even need to do the first to 
do the latter.

- Gordon