[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