mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 13:41:24 +00:00 
			
		
		
		
	Generalize max(seq) and min(seq) to work with iterators.
NEEDS DOC CHANGES.
This commit is contained in:
		
							parent
							
								
									c7745d4b54
								
							
						
					
					
						commit
						c307453162
					
				
					 3 changed files with 61 additions and 15 deletions
				
			
		|  | @ -319,4 +319,39 @@ def next(self): | ||||||
|         self.assertEqual(filter(lambda x: not x, seq), [False]*25) |         self.assertEqual(filter(lambda x: not x, seq), [False]*25) | ||||||
|         self.assertEqual(filter(lambda x: not x, iter(seq)), [False]*25) |         self.assertEqual(filter(lambda x: not x, iter(seq)), [False]*25) | ||||||
| 
 | 
 | ||||||
|  |     # Test max() and min()'s use of iterators. | ||||||
|  |     def test_builtin_max_min(self): | ||||||
|  |         self.assertEqual(max(SequenceClass(5)), 4) | ||||||
|  |         self.assertEqual(min(SequenceClass(5)), 0) | ||||||
|  |         self.assertEqual(max(8, -1), 8) | ||||||
|  |         self.assertEqual(min(8, -1), -1) | ||||||
|  | 
 | ||||||
|  |         d = {"one": 1, "two": 2, "three": 3} | ||||||
|  |         self.assertEqual(max(d), "two") | ||||||
|  |         self.assertEqual(min(d), "one") | ||||||
|  |         self.assertEqual(max(d.itervalues()), 3) | ||||||
|  |         self.assertEqual(min(iter(d.itervalues())), 1) | ||||||
|  | 
 | ||||||
|  |         self.assertRaises(TypeError, list, list) | ||||||
|  |         self.assertRaises(TypeError, list, 42) | ||||||
|  | 
 | ||||||
|  |         f = open(TESTFN, "w") | ||||||
|  |         try: | ||||||
|  |             f.write("medium line\n") | ||||||
|  |             f.write("xtra large line\n") | ||||||
|  |             f.write("itty-bitty line\n") | ||||||
|  |         finally: | ||||||
|  |             f.close() | ||||||
|  |         f = open(TESTFN, "r") | ||||||
|  |         try: | ||||||
|  |             self.assertEqual(min(f), "itty-bitty line\n") | ||||||
|  |             f.seek(0, 0) | ||||||
|  |             self.assertEqual(max(f), "xtra large line\n") | ||||||
|  |         finally: | ||||||
|  |             f.close() | ||||||
|  |             try: | ||||||
|  |                 unlink(TESTFN) | ||||||
|  |             except OSError: | ||||||
|  |                 pass | ||||||
|  | 
 | ||||||
| run_unittest(TestCase) | run_unittest(TestCase) | ||||||
|  |  | ||||||
|  | @ -19,6 +19,8 @@ Core | ||||||
|   arguments: |   arguments: | ||||||
|     filter() |     filter() | ||||||
|     list() |     list() | ||||||
|  |     max() | ||||||
|  |     min() | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| What's New in Python 2.1 (final)? | What's New in Python 2.1 (final)? | ||||||
|  |  | ||||||
|  | @ -1444,30 +1444,37 @@ static PyObject * | ||||||
| min_max(PyObject *args, int op) | min_max(PyObject *args, int op) | ||||||
| { | { | ||||||
| 	int i; | 	int i; | ||||||
| 	PyObject *v, *w, *x; | 	PyObject *v, *w, *x, *it; | ||||||
| 	PySequenceMethods *sq; |  | ||||||
| 
 | 
 | ||||||
| 	if (PyTuple_Size(args) > 1) | 	if (PyTuple_Size(args) > 1) | ||||||
| 		v = args; | 		v = args; | ||||||
| 	else if (!PyArg_ParseTuple(args, "O:min/max", &v)) | 	else if (!PyArg_ParseTuple(args, "O:min/max", &v)) | ||||||
| 		return NULL; | 		return NULL; | ||||||
| 	sq = v->ob_type->tp_as_sequence; | 	 | ||||||
| 	if (sq == NULL || sq->sq_item == NULL) { | 	it = PyObject_GetIter(v); | ||||||
| 		PyErr_SetString(PyExc_TypeError, | 	if (it == NULL) | ||||||
| 				"min() or max() arg must be a sequence"); |  | ||||||
| 		return NULL; | 		return NULL; | ||||||
| 	} | 
 | ||||||
| 	w = NULL; | 	w = NULL;  /* the result */ | ||||||
| 	for (i = 0; ; i++) { | 	for (i = 0; ; i++) { | ||||||
| 		x = (*sq->sq_item)(v, i); /* Implies INCREF */ | 		x = PyIter_Next(it); | ||||||
| 		if (x == NULL) { | 		if (x == NULL) { | ||||||
| 			if (PyErr_ExceptionMatches(PyExc_IndexError)) { | 			/* We're out of here in any case, but if this is a
 | ||||||
| 				PyErr_Clear(); | 			 * StopIteration exception it's expected, but if | ||||||
| 				break; | 			 * any other kind of exception it's an error. | ||||||
|  | 			 */ | ||||||
|  | 			if (PyErr_Occurred()) { | ||||||
|  | 				if (PyErr_ExceptionMatches(PyExc_StopIteration)) | ||||||
|  | 					PyErr_Clear(); | ||||||
|  | 				else { | ||||||
|  | 					Py_XDECREF(w); | ||||||
|  | 					Py_DECREF(it); | ||||||
|  | 					return NULL; | ||||||
|  | 				} | ||||||
| 			} | 			} | ||||||
| 			Py_XDECREF(w); | 			break; | ||||||
| 			return NULL; |  | ||||||
| 		} | 		} | ||||||
|  | 
 | ||||||
| 		if (w == NULL) | 		if (w == NULL) | ||||||
| 			w = x; | 			w = x; | ||||||
| 		else { | 		else { | ||||||
|  | @ -1478,7 +1485,8 @@ min_max(PyObject *args, int op) | ||||||
| 			} | 			} | ||||||
| 			else if (cmp < 0) { | 			else if (cmp < 0) { | ||||||
| 				Py_DECREF(x); | 				Py_DECREF(x); | ||||||
| 				Py_XDECREF(w); | 				Py_DECREF(w); | ||||||
|  | 				Py_DECREF(it); | ||||||
| 				return NULL; | 				return NULL; | ||||||
| 			} | 			} | ||||||
| 			else | 			else | ||||||
|  | @ -1488,6 +1496,7 @@ min_max(PyObject *args, int op) | ||||||
| 	if (w == NULL) | 	if (w == NULL) | ||||||
| 		PyErr_SetString(PyExc_ValueError, | 		PyErr_SetString(PyExc_ValueError, | ||||||
| 				"min() or max() arg is an empty sequence"); | 				"min() or max() arg is an empty sequence"); | ||||||
|  | 	Py_DECREF(it); | ||||||
| 	return w; | 	return w; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Tim Peters
						Tim Peters