Proposal: === and !=== operators
Cameron Simpson
cs at zip.com.au
Wed Jul 9 04:17:23 EDT 2014
On 09Jul2014 07:00, Steven D'Aprano <steve at pearwood.info> wrote:
>At the moment, Python has two (in)equality operators, == and != which
>call __eq__ and __ne__ methods. Some problems with those:
>
>* Many people expect == to always be reflexive (that is, x == x for
> every x) but classes which customise __eq__ may not be.
I'm presuming this proposal is fallout from the Nan anecdotes, since NaN !=
Nan?
The language spec is at least up front about it, I thought. It could be
plainer, but at least it says:
Furthermore, some types (for example, function objects) support only a
degenerate notion of comparison where any two objects of that type are
unequal.
which implies nonreflexivity.
Returning to Nan, I had thought it was an explicit design choice in IEEE
floating point that NaN != NaN so that in (hypothetically) common cases results
won't accidentally issue truthiness in the vein of propagating evaluation
errors.
Personally I'd go for Nan == Nan raising a ValueError myself, but that is a
bikeshed I lack the expertise to paint.
Anyway, I thought it is a design feature that a class can arrange for
nonreflexivity in ==. Surprising, maybe, but wouldn't use of such a special
class be known to the user?
Have we got some examples of people using nonreflexive == classes and being
burnt? Aside from Nan, which I'd argue is a well known special case, or should
be.
>* The == operator requires __eq__ to return True or False
> (or NotImplemented) and raises TypeError if it doesn't, which
> makes it impossible to use == with (say) three-valued or fuzzy
> logic.
In the Python 3.4.0 docs the __eq__ etc methods have this paragraph:
A rich comparison method may return the singleton NotImplemented if it does
not implement the operation for a given pair of arguments. By convention,
False and True are returned for a successful comparison. However, these
methods can return any value, so if the comparison operator is used in a
Boolean context (e.g., in the condition of an if statement), Python will call
bool() on the value to determine if the result is true or false.
and some tests with 2.7.8 and 3.4.1:
% python
Python 2.7.8 (default, Jul 3 2014, 06:13:58)
[GCC 4.2.1 Compatible Apple LLVM 5.1 (clang-503.0.40)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> class O(object):
... def __eq__(self, other): return 9
...
>>> o=O()
>>> o == o
9
% python3.4
Python 3.4.1 (default, May 21 2014, 01:39:38)
[GCC 4.2.1 Compatible Apple LLVM 5.1 (clang-503.0.40)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> class O(object):
... def __eq__(self, other): return 9
...
>>> o=O()
>>> o == o
9
I don't see this type constraint you describe.
>I propose:
>
>* The == operator be redefined to *always* assume reflexivity, that
> is, it first compares the two arguments using `is` before calling
> the __eq__ methods.
Won't this slow down every == test?
>* That's a backwards-incompatible change, so you need to enable it
> using "from __future__ import equals" in Python 3.5, and then to
> become the default behaviour in 3.6.
>
>* To support non-reflexive types, allow === and !=== operators, which
> are like == and != except they don't call `is` first.
[...]
I don't like the spelling. They seem very easy to misuse as typos of
conventional == and !=, and not visually very different.
Cheers,
Cameron Simpson <cs at zip.com.au>
55 mph is fast enough to get you killed, but slow enough to make you think
you're safe. - The Gumball Rally
More information about the Python-list
mailing list