Another pitfall in Python: == and !=

July 24, 2008 – 1:33 pm

Besides the False == 0 problem, I encountered another problem that surprised me. Consider the following Python code:

class Foo(object):
    def __eq__(self, other):
        if isinstance(other, Foo):
            return True
        return False
f1 = Foo()
f2 = Foo()
f1 == f2  # => True or False ?
f1 != f2  # => True or False ?

What do you expect the result to be in the last two lines?

If you know a little Python, you’ll notice that I defined __eq__ method for class Foo that consider every Foo objects as equal. So f1 == f2 evaluate to True. But why does f1 != f2 still evaluate to True? :(

danran@freecity quoted for me this from the Python document:

Implementation note: Objects of different types except numbers are ordered by their type names; objects of the same types that don’t support proper comparison are ordered by their address.

So when you haven’t defined __ne__ for Foo and f1 and f2 don’t have the same address, f1 != f2 will evaluate to True.

OK, I know the reason now. But please forgive my ignorance, I didn’t know the __ne__ method until just now. While it is good to have both __eq__ and __ne__ to have more rich behavior, why not be a little smarter when only one of them is defined by the user? For simplicity? Simple to write the application code or simple to implement the language?

I always like the quote from Bjarne Stroustrup (the father of C++):

Complexity will go somewhere: if not the language then the application code.

I don’t know which I’ll prefer, because currently my application code is in fact implementing another language. :p

Update 2008-07-24: gwilym pointed me this post on comp.lang.python today, which is ranting one of the Python Zen: Explicit is better than implicit. It also described the __eq__/__ne__ problem and I agree most of the OP’s opinion. We can consider Python’s KISS to be: Keep It Simple and verboSe — just kidding. :D

  1. 5 Responses to “Another pitfall in Python: == and !=”

  2. You might be interested in this simliar (though more ranty) rant:

    By gwilym on Jul 24, 2008

  3. @gwilym,
    Hrm, after discussing with a friend, I found this is in fact a reasonable behavior. Maybe the reason that I considered this strange is that I’m too much influenced by Ruby. :p

    By pluskid on Jul 24, 2008

  4. Reading the rationale might also be illuminating:

    “The == and != operators are not assumed to be each other’s complement (e.g. IEEE 754 floating point numbers do not satisfy this). It is up to the type to implement this if desired. Similar for =, or > and

    By Fredrik on Jul 24, 2008

  5. (…and the rest of that post was cut off by wordpress, without warning. Oh, well. Click on the link for the rest of that paragraph.)

    By Fredrik on Jul 24, 2008

  6. @Fredrik,
    Thanks for the link to the rationale. It looks reasonable. However, in my opinion, more people will need != to be the complement of == behavior most of the time instead of concerning about the low-level stuffs like floating point numbers (especially in such a high-level language like Python).

    In Ruby, != is always the complement of ==. In other words, you can not define your own __ne__ method like in Python. There are some drawbacks for this style. For example, in RSpec, you can only use “foo.should_not == bar” but not “foo.should != bar” . But this works fine most of the time.

    Another (might be better) solution is give the user both control on __eq__ and __ne__ but when user defined only one of them on some class, the other automatically become the complement. This seems to violate the explicit over implicit principle of Python. But as Jordan pointed out in that post on comp.lang.python: that principle seems to be a little abused.

    ps: what do you mean by …and the rest of that post was cut off by wordpress, without warning.? What post do you mean?

    By pluskid on Jul 24, 2008

Post a Comment