richcmpfunc semantics

David M. Cooke cookedm+news at physics.mcmaster.ca
Thu Apr 7 16:16:36 EDT 2005


harold fellermann <harold.fellermann at upf.edu> writes:

> Thank you Greg,
>
> I figured most of it out in the meantime, myself. I only differ
> from you in one point.
>
>>> What has to be done, if the function is invoked for an operator
>>> I don't want to define?
>>
>> Return Py_NotImplemented. (Note that's return, *not* raise.)
>
> I used
>
> PyErr_BadArgument();
> return NULL;
>
> instead. What is the difference between the two and which one
> is to prefer.

If you do it your way you're a bad neighbour: If your object is the
first one (left-hand side) of the operator, it will prevent the other
object from handling the case if it can. This is the same advice as
for all of the other operators (__add__, etc.)

Consider the pure-python version:

class A:
    def __init__(self, what_to_do='return'):
        self.what_to_do = what_to_do
    def __eq__(self, other):
        print 'A.__eq__'
        if self.what_to_do == 'return':
            return NotImplemented
        else:
            raise Exception

class B:
    def __eq__(self, other):
        print 'B.__eq__'
        return True

>>> a = A('return')
>>> b = B()
>>> a == b
A.__eq__
B.__eq__
True
>>> b == a
B.__eq__
True
>>> a == a
A.__eq__
A.__eq__
A.__eq__
A.__eq__
True

So the B class handles the case where A doesn't know what to do. Also
note the last case, where Python falls back on id() comparisions to
determine equality.

Now, compare with this:

>>> a = A('raise')
>>> b = B()
>>> a == b
A.__eq__
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
  File "x.py", line 9, in __eq__
    raise Exception
Exception
>>> b == a
B.__eq__
True
>>> a == a
A.__eq__
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
  File "x.py", line 9, in __eq__
    raise Exception
Exception

So now comparing A and B objects can fail. If you *know* A and B
objects can't be compared for equality, it'd be ok to raise a
TypeError, but that should be after a type test.

> Also, do you need to increment the reference count
> of Py_NotImeplemented before returning it?

Yes; it's a singleton like Py_None.

-- 
|>|\/|<
/--------------------------------------------------------------------------\
|David M. Cooke
|cookedm(at)physics(dot)mcmaster(dot)ca



More information about the Python-list mailing list