2

I have created a new Python object as follows

class Mylist(list):
    def __cmp__(self,other):
        if len(self)>len(other):
            return 1
        elif len(self)<len(other):
            return -1
        elif len(self)==len(other):
            return 0

my intend is, when two Mylist objects are compared the object with large number of items should be higher.

c=Mylist([4,5,6])
d=Mylist([1,2,3])

after running the above code, c and d are supposed to be equal(c==d <==True). But I am getting

>>> c==d
False
>>> c>d
True
>>> 

they are being compared like the list object itself. What did I do wrong?

John Zwinck
  • 239,568
  • 38
  • 324
  • 436
mahes
  • 1,074
  • 3
  • 12
  • 20

2 Answers2

2

You need to implement function __eq__.

class Mylist(list):
  def __cmp__(self,other):
    if len(self)>len(other):
        return 1
    elif len(self)<len(other):
        return -1
    elif len(self)==len(other):
        return 0
  def __eq__(self, other):
    return len(self)==len(other)

UPDATE: (previous code does not work perfectly as explained in comments)

Although @tobias_k answer explains it better, you can do it via __cmp__ function in Python 2 if you insist. You can enable it by removing other compare functions (le,lt,ge, ...):

class Mylist(list):
  def __cmp__(self,other):
    if len(self)>len(other):
        return 1
    elif len(self)<len(other):
        return -1
    elif len(self)==len(other):
        return 0
  def __eq__(self, other):
    return len(self)==len(other)
  @property
  def __lt__(self, other): raise AttributeError()
  @property
  def __le__(self, other): raise AttributeError()
  @property
  def __ne__(self, other): raise AttributeError()
  @property
  def __gt__(self, other): raise AttributeError()
  @property
  def __ge__(self, other): raise AttributeError()
Jiri
  • 16,425
  • 6
  • 52
  • 68
  • This fixes it for `==`, but not in general. `<`, `!=`, etc still work the way they do in `list`. – tobias_k Sep 10 '14 at 10:35
  • In Python 3, it seems mandatory to implement `__eq__` even when there is no base class--`__cmp__` returning 0 is not enough to make equality true, whereas it was in Python 2! – John Zwinck Sep 10 '14 at 10:36
  • 1
    @JohnZwinck In Python3, `__cmp__` is no longer used at all. See [here](http://stackoverflow.com/questions/8276983/python-2-and-python-3-cmp) – tobias_k Sep 10 '14 at 10:48
  • @tobias_k: good to know, this will probably be of interest to the OP, should the code ever wind up on Python 3. – John Zwinck Sep 10 '14 at 10:50
1

The problem seems to be that list implements all of the rich comparison operators, and __cmp__ will only be called if those are not defined. Thus, it seems like you have to overwrite all of those:

class Mylist(list):

    def __lt__(self, other): return cmp(self, other) <  0
    def __le__(self, other): return cmp(self, other) <= 0
    def __eq__(self, other): return cmp(self, other) == 0
    def __ne__(self, other): return cmp(self, other) != 0
    def __gt__(self, other): return cmp(self, other) >  0
    def __ge__(self, other): return cmp(self, other) >= 0

    def __cmp__(self, other): return cmp(len(self), len(other))

BTW, it seems like __cmp__ was removed entirely in Python 3. The above works in Python 2.x, but for compatibility you should probably rather do it like

    def __lt__(self, other): return len(self) < len(other)

Also see these two related questions. Note that while in Python 3 it would be enough to implement __eq__ and __lt__ and have Python infer the rest, this will not work in this case, since list already implements all of them, so you have to overwrite them all.

Community
  • 1
  • 1
tobias_k
  • 81,265
  • 12
  • 120
  • 179