[Python-Dev] Intricacies of calling __eq__

Steven D'Aprano steve at pearwood.info
Tue Mar 18 12:18:42 CET 2014


On Tue, Mar 18, 2014 at 05:05:56AM -0400, Terry Reedy wrote:
> On 3/18/2014 3:52 AM, Maciej Fijalkowski wrote:
> >Hi
> >
> >I have a question about calling __eq__ in some cases.
> >
> >We're thinking about doing an optimization where say:
> >
> >if x in d:
> >    return d[x]
> 
> if d.__contains__(x): return d.__getitem__(x)

[Aside: to be pedantic, Python only calls dunder methods on the class, 
not the instance, in response to operators and other special calls. That 
is, type(d).__contains__ rather than d.__contains__, etc. And to be even 
more pedantic, that's only true for new-style classes.]

 
> I do not see any requirement to call x.__eq__ any particular number of 
> times. The implementation of d might always call somekey.__eq__(x). The 
> concept of sets (and dicts) requires coherent equality comparisons.

To what extent does Python the language specify that user-defined 
classes must be coherent? How much latitude to shoot oneself in the foot 
should the language allow?

What counts as coherent can depend on the types involved. For instance, 
I consider IEEE-754 Not-A-Numbers to be coherent, albeit weird. Python 
goes only so far to accomodate NANs: while it allows a NAN to test 
unequal even to itself (`NAN == NAN` returns False), containers are 
allowed to assume that instances are equal to themselves (`NAN in {NAN}` 
returns True). This was discussed in great detail a few years ago, and 
if I recall correctly, the conclusion was that containers can assume 
that their elements are reflexive (they equal themselves), but equality 
== cannot make the same assumption and bypass calling __eq__.

 
> >where d is a dict would result in only one dict lookup (the second one
> >being constant folded away). The question is whether it's ok to do it,
> >despite the fact that it changes the semantics on how many times
> >__eq__ is called on x.
> 
> A __eq__ that has side-effects violates the intended and expected 
> semanitics of __eq__.

Nevertheless, an __eq__ with side-effects is legal Python and may in 
fact be useful. 

It's a tricky one... I don't know how I feel about short-cutting normal 
Python semantics for speed. On the one hand, faster is good. But on the 
other hand, it makes it harder to reason about code when things go 
wrong. "Why is my __eq__ method not being called?"


-- 
Steven


More information about the Python-Dev mailing list