[Python-checkins] CVS: python/dist/src/Objects abstract.c,2.63,2.64
Tim Peters
tim_one@users.sourceforge.net
Fri, 04 May 2001 20:56:39 -0700
Update of /cvsroot/python/python/dist/src/Objects
In directory usw-pr-cvs1:/tmp/cvs-serv17966/python/dist/src/Objects
Modified Files:
abstract.c
Log Message:
Generalize tuple() to work nicely with iterators.
NEEDS DOC CHANGES.
This one surprised me! While I expected tuple() to be a no-brainer, turns
out it's actually dripping with consequences:
1. It will *allow* the popular PySequence_Fast() to work with any iterable
object (code for that not yet checked in, but should be trivial).
2. It caused two std tests to fail. This because some places used
PyTuple_Sequence() (the C spelling of tuple()) as an indirect way to test
whether something *is* a sequence. But tuple() code only looked for the
existence of sq->item to determine that, and e.g. an instance passed
that test whether or not it supported the other operations tuple()
needed (e.g., __len__). So some things the tests *expected* to fail
with an AttributeError now fail with a TypeError instead. This looks
like an improvement to me; e.g., test_coercion used to produce 559
TypeErrors and 2 AttributeErrors, and now they're all TypeErrors. The
error details are more informative too, because the places calling this
were *looking* for TypeErrors in order to replace the generic tuple()
"not a sequence" msg with their own more specific text, and
AttributeErrors snuck by that.
Index: abstract.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Objects/abstract.c,v
retrieving revision 2.63
retrieving revision 2.64
diff -C2 -r2.63 -r2.64
*** abstract.c 2001/05/05 00:14:56 2.63
--- abstract.c 2001/05/05 03:56:37 2.64
***************
*** 1177,1235 ****
PySequence_Tuple(PyObject *v)
{
! PySequenceMethods *m;
if (v == NULL)
return null_error();
if (PyTuple_Check(v)) {
Py_INCREF(v);
return v;
}
-
if (PyList_Check(v))
return PyList_AsTuple(v);
-
- /* There used to be code for strings here, but tuplifying strings is
- not a common activity, so I nuked it. Down with code bloat! */
! /* Generic sequence object */
! m = v->ob_type->tp_as_sequence;
! if (m && m->sq_item) {
! int i;
! PyObject *t;
! int n = PySequence_Size(v);
! if (n < 0)
! return NULL;
! t = PyTuple_New(n);
! if (t == NULL)
! return NULL;
! for (i = 0; ; i++) {
! PyObject *item = (*m->sq_item)(v, i);
! if (item == NULL) {
! if (PyErr_ExceptionMatches(PyExc_IndexError))
! PyErr_Clear();
! else {
! Py_DECREF(t);
! t = NULL;
! }
! break;
! }
! if (i >= n) {
! if (n < 500)
! n += 10;
! else
! n += 100;
! if (_PyTuple_Resize(&t, n, 0) != 0)
! break;
! }
! PyTuple_SET_ITEM(t, i, item);
}
! if (i < n && t != NULL)
! _PyTuple_Resize(&t, i, 0);
! return t;
}
! /* None of the above */
! return type_error("tuple() argument must be a sequence");
}
--- 1177,1242 ----
PySequence_Tuple(PyObject *v)
{
! PyObject *it; /* iter(v) */
! int n; /* guess for result tuple size */
! PyObject *result;
! int j;
if (v == NULL)
return null_error();
+ /* Special-case the common tuple and list cases, for efficiency. */
if (PyTuple_Check(v)) {
Py_INCREF(v);
return v;
}
if (PyList_Check(v))
return PyList_AsTuple(v);
! /* Get iterator. */
! it = PyObject_GetIter(v);
! if (it == NULL)
! return type_error("tuple() argument must support iteration");
!
! /* Guess result size and allocate space. */
! n = PySequence_Size(v);
! if (n < 0) {
! PyErr_Clear();
! n = 10; /* arbitrary */
! }
! result = PyTuple_New(n);
! if (result == NULL)
! goto Fail;
!
! /* Fill the tuple. */
! for (j = 0; ; ++j) {
! PyObject *item = PyIter_Next(it);
! if (item == NULL) {
! if (PyErr_Occurred())
! goto Fail;
! break;
! }
! if (j >= n) {
! if (n < 500)
! n += 10;
! else
! n += 100;
! if (_PyTuple_Resize(&result, n, 0) != 0)
! goto Fail;
}
! PyTuple_SET_ITEM(result, j, item);
}
! /* Cut tuple back if guess was too large. */
! if (j < n &&
! _PyTuple_Resize(&result, j, 0) != 0)
! goto Fail;
!
! Py_DECREF(it);
! return result;
!
! Fail:
! Py_XDECREF(result);
! Py_DECREF(it);
! return NULL;
}