]> granicus.if.org Git - python/commitdiff
Issue 2025: Add index() and count() methods to tuple so that it will follow
authorRaymond Hettinger <python@rcn.com>
Thu, 7 Feb 2008 00:41:02 +0000 (00:41 +0000)
committerRaymond Hettinger <python@rcn.com>
Thu, 7 Feb 2008 00:41:02 +0000 (00:41 +0000)
the ABC for collections.Sequence.

Lib/test/seq_tests.py
Misc/NEWS
Objects/tupleobject.c

index ebd6157ced6da698847bb6c3eff0701442b35a8d..81fe62709ff28193e7a22aa1b3457f09c59dcf7a 100644 (file)
@@ -4,6 +4,7 @@ Tests common to tuple, list and UserList.UserList
 
 import unittest
 from test import test_support
+import sys
 
 # Various iterables
 # This is used for checking the constructor (here and in test_deque.py)
@@ -326,3 +327,64 @@ class CommonTest(unittest.TestCase):
         self.assertEqual(a.__getitem__(slice(3,5)), self.type2test([]))
         self.assertRaises(ValueError, a.__getitem__, slice(0, 10, 0))
         self.assertRaises(TypeError, a.__getitem__, 'x')
+
+    def test_count(self):
+        a = self.type2test([0, 1, 2])*3
+        self.assertEqual(a.count(0), 3)
+        self.assertEqual(a.count(1), 3)
+        self.assertEqual(a.count(3), 0)
+
+        self.assertRaises(TypeError, a.count)
+
+        class BadExc(Exception):
+            pass
+
+        class BadCmp:
+            def __eq__(self, other):
+                if other == 2:
+                    raise BadExc()
+                return False
+
+        self.assertRaises(BadExc, a.count, BadCmp())
+
+    def test_index(self):
+        u = self.type2test([0, 1])
+        self.assertEqual(u.index(0), 0)
+        self.assertEqual(u.index(1), 1)
+        self.assertRaises(ValueError, u.index, 2)
+
+        u = self.type2test([-2, -1, 0, 0, 1, 2])
+        self.assertEqual(u.count(0), 2)
+        self.assertEqual(u.index(0), 2)
+        self.assertEqual(u.index(0, 2), 2)
+        self.assertEqual(u.index(-2, -10), 0)
+        self.assertEqual(u.index(0, 3), 3)
+        self.assertEqual(u.index(0, 3, 4), 3)
+        self.assertRaises(ValueError, u.index, 2, 0, -10)
+
+        self.assertRaises(TypeError, u.index)
+
+        class BadExc(Exception):
+            pass
+
+        class BadCmp:
+            def __eq__(self, other):
+                if other == 2:
+                    raise BadExc()
+                return False
+
+        a = self.type2test([0, 1, 2, 3])
+        self.assertRaises(BadExc, a.index, BadCmp())
+
+        a = self.type2test([-2, -1, 0, 0, 1, 2])
+        self.assertEqual(a.index(0), 2)
+        self.assertEqual(a.index(0, 2), 2)
+        self.assertEqual(a.index(0, -4), 2)
+        self.assertEqual(a.index(-2, -10), 0)
+        self.assertEqual(a.index(0, 3), 3)
+        self.assertEqual(a.index(0, -3), 3)
+        self.assertEqual(a.index(0, 3, 4), 3)
+        self.assertEqual(a.index(0, -3, -2), 3)
+        self.assertEqual(a.index(0, -4*sys.maxsize, 4*sys.maxsize), 2)
+        self.assertRaises(ValueError, a.index, 0, 4*sys.maxsize,-4*sys.maxsize)
+        self.assertRaises(ValueError, a.index, 2, 0, -10)
index 3ba1678b5373a099bc20e85f3653f32cd5137a5c..9ef34070fef484e1f2b809e3c125fd69fe08749a 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -12,6 +12,9 @@ What's New in Python 3.0a3?
 Core and Builtins
 -----------------
 
+- Issue #2025 :  Add tuple.count() and tuple.index() methods to comply with
+  the collections.Sequence API.
+
 - Fixed multiple reinitialization of the Python interpreter. The small int
   list in longobject.c has caused a seg fault during the third finalization.
 
index c212345ff2c5d7de65cf178b816df6dceffffeaa..df69db929a0431b23142b67ba5bc78c53aebaadc 100644 (file)
@@ -430,6 +430,53 @@ tuplerepeat(PyTupleObject *a, Py_ssize_t n)
        return (PyObject *) np;
 }
 
+static PyObject *
+tupleindex(PyTupleObject *self, PyObject *args)
+{
+       Py_ssize_t i, start=0, stop=Py_SIZE(self);
+       PyObject *v;
+
+       if (!PyArg_ParseTuple(args, "O|O&O&:index", &v,
+                                   _PyEval_SliceIndex, &start,
+                                   _PyEval_SliceIndex, &stop))
+               return NULL;
+       if (start < 0) {
+               start += Py_SIZE(self);
+               if (start < 0)
+                       start = 0;
+       }
+       if (stop < 0) {
+               stop += Py_SIZE(self);
+               if (stop < 0)
+                       stop = 0;
+       }
+       for (i = start; i < stop && i < Py_SIZE(self); i++) {
+               int cmp = PyObject_RichCompareBool(self->ob_item[i], v, Py_EQ);
+               if (cmp > 0)
+                       return PyLong_FromSsize_t(i);
+               else if (cmp < 0)
+                       return NULL;
+       }
+       PyErr_SetString(PyExc_ValueError, "tuple.index(x): x not in list");
+       return NULL;
+}
+
+static PyObject *
+tuplecount(PyTupleObject *self, PyObject *v)
+{
+       Py_ssize_t count = 0;
+       Py_ssize_t i;
+
+       for (i = 0; i < Py_SIZE(self); i++) {
+               int cmp = PyObject_RichCompareBool(self->ob_item[i], v, Py_EQ);
+               if (cmp > 0)
+                       count++;
+               else if (cmp < 0)
+                       return NULL;
+       }
+       return PyLong_FromSsize_t(count);
+}
+
 static int
 tupletraverse(PyTupleObject *o, visitproc visit, void *arg)
 {
@@ -636,8 +683,15 @@ tuple_getnewargs(PyTupleObject *v)
        
 }
 
+PyDoc_STRVAR(index_doc,
+"T.index(value, [start, [stop]]) -> integer -- return first index of value");
+PyDoc_STRVAR(count_doc,
+"T.count(value) -> integer -- return number of occurrences of value");
+
 static PyMethodDef tuple_methods[] = {
        {"__getnewargs__",      (PyCFunction)tuple_getnewargs,  METH_NOARGS},
+       {"index",       (PyCFunction)tupleindex,  METH_VARARGS, index_doc},
+       {"count",       (PyCFunction)tuplecount,  METH_O, count_doc},
        {NULL,          NULL}           /* sentinel */
 };