Andy Freeman anamax at
Mon Oct 1 02:37:13 CEST 2001

weeks at (Greg Weeks) wrote in message news:<1001876090.367103 at>...
>     x = 6.02
>     y = 6.02
> Are x and y identical?  They are identical as *numbers* (which I'll call
> conceptual identity) but not as Python *implentations* of numbers (since
> id(x) != id(y)).  Good programming style requires us to think of numbers
> primarily as numbers and not as their implementations.  So we are more
> interested in conceptual identity than in implementation identity.
> Why is (conceptual) identity of numbers different from (conceptual)
> identity of bank accounts?  Because bank accounts are mutable.  A bank
> account can have different states at different times.  A number can't.

> So, we've encountered three kinds of identity in this discussion:
>     A.  conceptual identity
>     B.  implementation identity
>     C.  state identity
> In Python, B corresponds to "is".  And to many Python programmers, C
> corresponds to "==".  But that leaves A without an operator.  I'm unable to
> swallow that.  So, I use "==" for A; I never use "is"; and if I need C --
> which hasn't happened yet -- I write a method for it.
> This works pretty well.  It works for all the immutable types.  It also
> works for bank accounts *as defined above*.  That's why you won't find me
> adding __cmp__ and __hash__ methods to bank accounts.  Note, by the way,
> that the above bank accounts are suitable hash table keys (and I have found
> that useful on occasion).
> Unfortunately, "==" does not represent conceptual identity for lists and
> dictionaries.  (Lists and dictionaries are like bank accounts.  They are
> not conceptually identical even if they happen to have the same state.)
> That's what I mean when I say Python "got it wrong".

Common Lisp introduced the function "eql" for "same, even if the implementation
decided to use multiple objects", ie, eql numbers don't necessarily reside
at the same address.  (Lisps tend not to have an id function.)  "eq" is
address compare (sort of like Python's "is").  (eql 1.0 1) is false as
I remember, which is "correct".  (It doesn't make sense to ask about
(eql 1 1L)'s value because 1L doesn't exist in Lisp's number model.)
I think that eql on lisp strings is a lot like python's == even though
lisp strings are mutable.  (If so, that's unfortunate.)

As Weeks observes, there are at least three kinds of identity, and that
identity and mutability are related.  (For what it's worth, I wouldn't
have used the term "conceptual identity".)

I've found that I'm better off when I think of equality as being application
dependent, that equality for composite objects doesn't have an independent
definition.  (Yes, there may be happen to be standard operators for certain
definitions, but ....)  For example, [1, 3] is "equal" to <instance ...>
for some applications.

These equality issues are, in my mind, related to the cliche that using
Python's "type" function is almost always an indication that you're doing
something wrong.  In CL, you almost always want to ask whether the "type"
of an object is a subtype of some other type.  I think that python's "hasattr"
is probably a better idea, but it only solves half the problem - an
object's "foo" attribute doesn't necessarily have the semantics that
I'm looking for.


More information about the Python-list mailing list