mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 05:31:20 +00:00 
			
		
		
		
	(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
					
				
					 4 changed files with 81 additions and 11 deletions
				
			
		|  | @ -368,3 +368,37 @@ class I: | |||
|     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…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Armin Rigo
						Armin Rigo