]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
(arre, arigo) SF bug #1350060
authorArmin Rigo <arigo@tunes.org>
Thu, 8 Jun 2006 10:56:24 +0000 (10:56 +0000)
committerArmin Rigo <arigo@tunes.org>
Thu, 8 Jun 2006 10:56:24 +0000 (10:56 +0000)
Give a consistent behavior for comparison and hashing of method objects
(both user- and built-in methods).  Now compares the 'self' recursively.
The hash was already asking for the hash of 'self'.

Lib/test/test_class.py
Lib/test/test_descr.py
Objects/classobject.c
Objects/descrobject.c

index 92c220ef6fdd5c44be4ef9206eda98cb93bdc598..6c91deb129b35867867002215e538b4dde125d30 100644 (file)
@@ -368,3 +368,37 @@ except AttributeError, x:
     pass
 else:
     print "attribute error for I.__init__ got masked"
+
+
+# Test comparison and hash of methods
+class A:
+    def __init__(self, x):
+        self.x = x
+    def f(self):
+        pass
+    def g(self):
+        pass
+    def __eq__(self, other):
+        return self.x == other.x
+    def __hash__(self):
+        return self.x
+class B(A):
+    pass
+
+a1 = A(1)
+a2 = A(2)
+assert a1.f == a1.f
+assert a1.f != a2.f
+assert a1.f != a1.g
+assert a1.f == A(1).f
+assert hash(a1.f) == hash(a1.f)
+assert hash(a1.f) == hash(A(1).f)
+
+assert A.f != a1.f
+assert A.f != A.g
+assert B.f == A.f
+assert hash(B.f) == hash(A.f)
+
+# the following triggers a SystemError in 2.4
+a = A(hash(A.f.im_func)^(-1))
+hash(a.f)
index 32796bf94d9203a2223fb6509b4a5865f0dbc89b..ca91042ce670d11d2ca979e7825dd246ecd7b9ac 100644 (file)
@@ -4014,11 +4014,24 @@ def methodwrapper():
 
     l = []
     vereq(l.__add__, l.__add__)
-    verify(l.__add__ != [].__add__)
+    vereq(l.__add__, [].__add__)
+    verify(l.__add__ != [5].__add__)
+    verify(l.__add__ != l.__mul__)
     verify(l.__add__.__name__ == '__add__')
     verify(l.__add__.__self__ is l)
     verify(l.__add__.__objclass__ is list)
     vereq(l.__add__.__doc__, list.__add__.__doc__)
+    try:
+        hash(l.__add__)
+    except TypeError:
+        pass
+    else:
+        raise TestFailed("no TypeError from hash([].__add__)")
+
+    t = ()
+    t += (7,)
+    vereq(t.__add__, (7,).__add__)
+    vereq(hash(t.__add__), hash((7,).__add__))
 
 def notimplemented():
     # all binary methods should be able to return a NotImplemented
index 6d2c648de52685d8c19187c32cf3b0f3ec2b7bb8..9e57269d24d0f573bb47656b26ac13d3d788f457 100644 (file)
@@ -2221,9 +2221,17 @@ instancemethod_dealloc(register PyMethodObject *im)
 static int
 instancemethod_compare(PyMethodObject *a, PyMethodObject *b)
 {
-       if (a->im_self != b->im_self)
+       int cmp;
+       cmp = PyObject_Compare(a->im_func, b->im_func);
+       if (cmp)
+               return cmp;
+
+       if (a->im_self == b->im_self)
+               return 0;
+       if (a->im_self == NULL || b->im_self == NULL)
                return (a->im_self < b->im_self) ? -1 : 1;
-       return PyObject_Compare(a->im_func, b->im_func);
+       else
+               return PyObject_Compare(a->im_self, b->im_self);
 }
 
 static PyObject *
@@ -2299,7 +2307,10 @@ instancemethod_hash(PyMethodObject *a)
        y = PyObject_Hash(a->im_func);
        if (y == -1)
                return -1;
-       return x ^ y;
+       x = x ^ y;
+       if (x == -1)
+               x = -2;
+       return x;
 }
 
 static int
index 561ba4a5f01de955185fbd798d9d77af5f9512a0..606ef053049ef23e60e9a65abd9b83dffa04fba8 100644 (file)
@@ -901,16 +901,28 @@ wrapper_dealloc(wrapperobject *wp)
 static int
 wrapper_compare(wrapperobject *a, wrapperobject *b)
 {
-       if (a->descr == b->descr) {
-               if (a->self == b->self)
-                       return 0;
-               else
-                       return (a->self < b->self) ? -1 : 1;
-       }
+       if (a->descr == b->descr)
+               return PyObject_Compare(a->self, b->self);
        else
                return (a->descr < b->descr) ? -1 : 1;
 }
 
+static long
+wrapper_hash(wrapperobject *wp)
+{
+       int x, y;
+       x = _Py_HashPointer(wp->descr);
+       if (x == -1)
+               return -1;
+       y = PyObject_Hash(wp->self);
+       if (y == -1)
+               return -1;
+       x = x ^ y;
+       if (x == -1)
+               x = -2;
+       return x;
+}
+
 static PyObject *
 wrapper_repr(wrapperobject *wp)
 {
@@ -1008,7 +1020,7 @@ static PyTypeObject wrappertype = {
        0,                                      /* tp_as_number */
        0,                                      /* tp_as_sequence */
        0,                                      /* tp_as_mapping */
-       0,                                      /* tp_hash */
+       (hashfunc)wrapper_hash,                 /* tp_hash */
        (ternaryfunc)wrapper_call,              /* tp_call */
        0,                                      /* tp_str */
        PyObject_GenericGetAttr,                /* tp_getattro */