Proposal: === and !=== operators

Cameron Simpson cs at zip.com.au
Wed Jul 9 10:17:23 CEST 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