summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTim Peters <tim.peters@gmail.com>2001-05-03 07:00:32 (GMT)
committerTim Peters <tim.peters@gmail.com>2001-05-03 07:00:32 (GMT)
commitc30745316258adc66a3c45f45e8fd0148038622a (patch)
tree2ca22a6b69ee08bc21853117e467b8911a49e40c
parentc7745d4b54f020e60ad3b56efd6e775d9d4873d4 (diff)
downloadcpython-c30745316258adc66a3c45f45e8fd0148038622a.zip
cpython-c30745316258adc66a3c45f45e8fd0148038622a.tar.gz
cpython-c30745316258adc66a3c45f45e8fd0148038622a.tar.bz2
Generalize max(seq) and min(seq) to work with iterators.
NEEDS DOC CHANGES.
-rw-r--r--Lib/test/test_iter.py35
-rw-r--r--Misc/NEWS2
-rw-r--r--Python/bltinmodule.c39
3 files changed, 61 insertions, 15 deletions
diff --git a/Lib/test/test_iter.py b/Lib/test/test_iter.py
index 952ab66..64fc01e 100644
--- a/Lib/test/test_iter.py
+++ b/Lib/test/test_iter.py
@@ -319,4 +319,39 @@ class TestCase(unittest.TestCase):
self.assertEqual(filter(lambda x: not x, 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)
diff --git a/Misc/NEWS b/Misc/NEWS
index bbd2ac3..9d84845 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -19,6 +19,8 @@ Core
arguments:
filter()
list()
+ max()
+ min()
What's New in Python 2.1 (final)?
diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c
index 1051374..9e8a227 100644
--- a/Python/bltinmodule.c
+++ b/Python/bltinmodule.c
@@ -1444,30 +1444,37 @@ static PyObject *
min_max(PyObject *args, int op)
{
int i;
- PyObject *v, *w, *x;
- PySequenceMethods *sq;
+ PyObject *v, *w, *x, *it;
if (PyTuple_Size(args) > 1)
v = args;
else if (!PyArg_ParseTuple(args, "O:min/max", &v))
return NULL;
- sq = v->ob_type->tp_as_sequence;
- if (sq == NULL || sq->sq_item == NULL) {
- PyErr_SetString(PyExc_TypeError,
- "min() or max() arg must be a sequence");
+
+ it = PyObject_GetIter(v);
+ if (it == NULL)
return NULL;
- }
- w = NULL;
+
+ w = NULL; /* the result */
for (i = 0; ; i++) {
- x = (*sq->sq_item)(v, i); /* Implies INCREF */
+ x = PyIter_Next(it);
if (x == NULL) {
- if (PyErr_ExceptionMatches(PyExc_IndexError)) {
- PyErr_Clear();
- break;
+ /* We're out of here in any case, but if this is a
+ * StopIteration exception it's expected, but if
+ * 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);
- return NULL;
+ break;
}
+
if (w == NULL)
w = x;
else {
@@ -1478,7 +1485,8 @@ min_max(PyObject *args, int op)
}
else if (cmp < 0) {
Py_DECREF(x);
- Py_XDECREF(w);
+ Py_DECREF(w);
+ Py_DECREF(it);
return NULL;
}
else
@@ -1488,6 +1496,7 @@ min_max(PyObject *args, int op)
if (w == NULL)
PyErr_SetString(PyExc_ValueError,
"min() or max() arg is an empty sequence");
+ Py_DECREF(it);
return w;
}