[Python-Dev] operator precedence of __eq__, __ne__, etc, if both object have implementations

Guido van Rossum guido at python.org
Wed Sep 23 22:22:31 CEST 2009


All,

I don't have the bandwidth right now to help out much in this thread,
so I'm glad that the collective effort has mostly figured out what the
rules are (as well as what they should be :-). It truly is a mess,
mostly thanks to the various concerns for backwards compatibility
(classic vs. new classes *and* __cmp__ vs rich comparisons makes for a
truly maddening compatibility matrix).

The double __eq__ calls in the pastebin examples are a surprise even
to me; it seems the logic for first giving the left object a chance
and then the right object is duplicated in the generic rich comparison
logic in object.c and again in instance_richcompare() in
classobject.c.

As Brett cautioned in the bug, I would be hesitant to try and fix this
in 2.x; there's simply too much code that relies on whatever odd
behavior CPython happens to exhibit, especially in test suites that
often over-constrain the behavior (see e.g. the other thread about
error messages, where I have nothing to add that Brett didn't already
say). In 3.2 I'm fine with the (ever so slight) semantic change,
especially since the behavior will rarely be exhibited in practice.
(You'd have to have two different objects with __eq__ methods that
return NotImplemented *and* have some kind of side effect that is
expected.)

--Guido

On Tue, Sep 22, 2009 at 8:12 AM, Mark Dickinson <dickinsm at gmail.com> wrote:
> On Tue, Sep 22, 2009 at 3:37 PM, Chris Withers <chris at simplistix.co.uk> wrote:
>> Where are the specifications on what happens if two objects are compared and both have implementations of __eq__? Which __eq__ is called?
>> What happens if the first one called returns False? Is the second one called? What is one implements __eq__ and the other __ne__?
>
> I (still :-) think this is covered, for Python 2.x at least, by:
>
> http://docs.python.org/reference/datamodel.html#coercion-rules
>
> Specifically, the bits that say:
>
> - For objects x and y, first x.__op__(y) is tried. If this is not
> implemented or returns NotImplemented, y.__rop__(x) is tried. If this
> is also not implemented or returns NotImplemented, a TypeError
> exception is raised. But see the following exception:
>
> - Exception to the previous item: if the left operand is an instance
> of a built-in type or a new-style class, and the right operand is an
> instance of a proper subclass of that type or class and overrides the
> base’s __rop__() method, the right operand’s __rop__() method is tried
> before the left operand’s __op__() method.
>
> I agree that having these rules in a section called 'Coercion rules'
> is a bit confusing.
>
>> Python 2
>> http://pastebin.com/f8f19ab3
>>
>> Python 3
>> http://pastebin.com/f55e44630
>
> The duplicate __eq__ calls in these pastes are disturbing:  in short,
> if A() and B() are new-style classes defining __eq__, it seems that
> A() == B() ends up calling A.__eq__ twice *and* B.__eq__ twice, in the
> order A.__eq__, B.__eq__, B.__eq__, A.__eq__.
>
> In 3.x, slot_tp_richcompare (in typeobject.c) makes two calls to
> half_richcompare;  I think the second is redundant.  The coercion
> rules are already taken care of in do_richcompare (in object.c).  I
> tried removing the second call to half_richcompare, and the entire
> test-suite still runs without errors.
>
> In 2.x, it's possible that this call is necessary for some bizarre
> combinations of __cmp__ and __eq__;  I haven't tried to get my head
> around this yet.
>
> I'll open an issue for the duplicate __eq__ calls.
>
> Mark
> _______________________________________________
> Python-Dev mailing list
> Python-Dev at python.org
> http://mail.python.org/mailman/listinfo/python-dev
> Unsubscribe: http://mail.python.org/mailman/options/python-dev/guido%40python.org
>



-- 
--Guido van Rossum (home page: http://www.python.org/~guido/)


More information about the Python-Dev mailing list