mirror of https://github.com/python/cpython
(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:
parent
996710fd44
commit
fd01d7933b
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Reference in New Issue