15

Recently I read the "Fluent python" and understood how == operator works with python objects, using __eq__() method. But how it works with int instances in python2?

>>> a = 1
>>> b = 1
>>> a == b
True
>>> a.__eq__(b)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'int' object has no attribute '__eq__'

in python3 all a.__eq__(b) returns True

Ivan Semochkin
  • 8,649
  • 3
  • 43
  • 75
  • 1
    http://stackoverflow.com/questions/3588776/how-is-eq-handled-in-python-and-in-what-order look at a few answers here, i think they explain it well – sjr59 Apr 28 '16 at 17:31
  • 1
    Wild guess, but `from operator import eq; eq(2,2)` does work in Python2. Either that or using `__cmp__` – OneCricketeer Apr 28 '16 at 17:33
  • 1
    `a.__cmp__` exists, which might be what Python 2 is using. – Blender Apr 28 '16 at 17:33

3 Answers3

10

Python prefers to use rich comparison functions (__eq__, __lt__, __ne__, etc.), but if those don't exist, it falls back to using a single comparison function (__cmp__, removed in Python 3):

These are the so-called “rich comparison” methods, and are called for comparison operators in preference to __cmp__() below.

The Python 2 integer type doesn't implement a rich comparison function:

PyTypeObject PyInt_Type = {
    ...
    (cmpfunc)int_compare,                       /* tp_compare */
    ...
    0,                                          /* tp_richcompare */

In Python 3, the integer type (now a long) implements only a rich comparison function, since Python 3 dropped support for __cmp__:

PyTypeObject PyLong_Type = {
    ...
    long_richcompare,                           /* tp_richcompare */

This is why (123).__eq__ doesn't exist. Instead, Python 2 falls back to (123).__cmp__ when testing the equality of two integers:

>>> (1).__eq__(2)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'int' object has no attribute '__eq__'
>>> (1).__cmp__(2)
-1
Baum mit Augen
  • 49,044
  • 25
  • 144
  • 182
Blender
  • 289,723
  • 53
  • 439
  • 496
6

In Python 2, the int object uses the __cmp__() method instead of the rich methods like __eq__(), __lt__(), __gt__(), and others.

  • How do you know this? Do you have a reference in the documentation, or ... ? – Akshat Mahajan Apr 28 '16 at 17:34
  • 3
    You can check this by running `dir(int_instance)` in Python; there's no `__eq__` method available. You can read more about `__cmp__()` versus the rich operators [here.](https://docs.python.org/2/reference/datamodel.html) – Jesse Shapiro Apr 28 '16 at 17:37
0

Here's my answer.

import sys
SPECIAL_OPNAMES = \
    { '__eq__': (lambda *args, **kwargs: not cmp(*args, **kwargs)) \
    , '__ne__': (lambda *args, **kwargs: cmp(*args, **kwargs)) \
    , '__lt__': (lambda *args, **kwargs: cmp(*args, **kwargs) < 0) \
    , '__ge__': (lambda *args, **kwargs: cmp(*args, **kwargs) >= 0) \
    , '__gt__': (lambda *args, **kwargs: cmp(*args, **kwargs) > 0) \
    , '__le__': (lambda *args, **kwargs: cmp(*args, **kwargs) <= 0) \
    } if sys.version_info.major == 2 else \
    {}

Working example:

>>> item = 1
>>> opname = '__eq__'
>>> t = type(item)
>>> op = SPECIAL_OPNAMES[opname] if opname in SPECIAL_OPNAMES else getattr(t, opname)
>>> op(item, 1)
True
Ismael Harun
  • 143
  • 2
  • 7