4

I'm working with some existing code that redefines equality (via a __cmp__ method) for a class. It doesn't work as expected and in trying to fix it I've come across some behavior I don't understand. If you define __cmp__ on a class that just calls the built in function cmp, then I would expect it to always hit the maximum recursion depth. However if you try to compare an instance of the class to itself it returns 0.

Here's the code:

class A:
    def __cmp__(self, other):
        return cmp(self, other)

a = A()
b = A()
cmp(a, a) # returns 0
cmp(b, b) # returns 0
cmp(a, b) # results in RuntimeError: maximum recursion depth exceeded

The RuntimeError I understand, but I don't understand why the first two calls to cmp succeed.

I've read through the data model section of the python docs and other things like this nice breakdown of python equality but can't find an answer to this recursion.

And, yes I understand that as written this is a totally pointless class. The code I'm working with tries to redefine equality in certain situations and otherwise falls through to a basecase. The basecase doesn't work as implemented and so I am trying to fix it. I thought calling cmp might work and discovered this issue. I'm hoping that understanding this will help me with finding a suitable solution.

4

3 回答 3

1

Where two names reference the same object, they are equal by definition (edit: at least as far as cmp is concerned, where "equal" really means "neither greater than nor less than").

于 2013-08-02T16:34:57.333 回答
1

Since the semantics of cmp require that the objects being compared have an ordering relationship (i.e. exactly one of the following is true in a cmp(x, y) call: x < y, x == y, or x > y), cmp can assume that an argument is equal to itself and skip calls to any comparison methods if the arguments are the same object.

(A lot of things in Python assume that for any object x, x == x. This sometimes causes bugs (especially with NaN floating-point values), but most of the time, it's a useful optimization. In the case of cmp, it's fine, since cmp requires x == x as a precondition to cmp(x, x).)

于 2013-08-02T16:36:00.503 回答
0

cmp(a,a) is calling the built-in cmp. Without looking at source, I'm guessing that self is other check is made without calling the class __cmp__. If the two objects are not identical, then __cmp__ is called.

于 2013-08-02T17:06:08.727 回答