Search code examples
pythonmetaprogrammingcmp

How can i change the __cmp__ function of an instance (not in class)?


How can i change the __cmp__ function of an instance (not in class)?

Ex:

class foo:
    def __init__(self, num):
        self.num = num

def cmp(self, other):
    return self.num - other.num

# Change __cmp__ function in class works
foo.__cmp__ = cmp
a = foo(1)
b = foo(1)

# returns True
a == b



# Change __cmp__ function in instance that way doesnt work
def cmp2(self, other):
    return -1

a.__cmp__ = cmp2
b.__cmp__ = cmp2

# Raise error 
a == b
#Traceback (most recent call last):
#  File "<stdin>", line 1, in <module>
#TypeError: cmp2() takes exactly 2 arguments (1 given)

Solution

  • DO NOT DO THIS

    It will make your code buggy and hard to maintain. The reason it is difficult is because the right way to do it is to subclass foo:

    class FunkyCmpFoo( foo ):
        def __cmp__( self, other ):
            return -1
    

    &c., &c. This way, you know that all foos compare in the same way, and all FunkyCmpFoos compare in the same way. If you don't, you will eventually end up comparing a modified foo with an original foo, and Cthulhu himself will rise from the depths to punish you.

    I'm not sure whether I should say this, but it is possible, by creating your own instance methods:

    funcType = type( foo.__cmp__ )
    # Alternatively:
    import new
    cmp2 = new.instancemethod( func, a, foo )
    
    a.__cmp__ = funcType( cmp2, a, foo )
    b.__cmp__ = funcType( cmp2, b, foo )
    

    I can think of one good reason to do this, and that is if your archenemy has to debug the code. In fact, I can think of some quite fun things to do with that in mind (how would you like sys.maxint to compare less than all even numbers?). Apart from that, it's a nightmare.