(arre, arigo) SF bug #1350060

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'.
This commit is contained in:
Armin Rigo 2006-06-08 10:56:24 +00:00
parent 996710fd44
commit fd01d7933b
4 changed files with 81 additions and 11 deletions

View 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)

View 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

View 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

View 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 */