diff --git a/Include/abstract.h b/Include/abstract.h index 17ce10551f7..7e0bc4d6ad6 100644 --- a/Include/abstract.h +++ b/Include/abstract.h @@ -422,6 +422,21 @@ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx*/ PyAPI_FUNC(int) PyObject_Length(PyObject *o); #define PyObject_Length PyObject_Size + PyAPI_FUNC(int) _PyObject_LengthCue(PyObject *o); + + /* + Return the size of object o. If the object, o, provides + both sequence and mapping protocols, the sequence size is + returned. On error, -1 is returned. If the object provides + a _length_cue() method, its value is returned. This is the + equivalent to the Python expression: + try: + return len(o) + except (AttributeError, TypeError): + if hasattr(o, '_length_cue'): + return o._length_cue() + raise + */ PyAPI_FUNC(PyObject *) PyObject_GetItem(PyObject *o, PyObject *key); diff --git a/Lib/test/test_enumerate.py b/Lib/test/test_enumerate.py index b6a18eeeb49..e0a272e025f 100644 --- a/Lib/test/test_enumerate.py +++ b/Lib/test/test_enumerate.py @@ -144,6 +144,7 @@ class TestReversed(unittest.TestCase): def test_len(self): # This is an implementation detail, not an interface requirement + from test.test_iterlen import len for s in ('hello', tuple('hello'), list('hello'), xrange(5)): self.assertEqual(len(reversed(s)), len(s)) r = reversed(s) diff --git a/Lib/test/test_iterlen.py b/Lib/test/test_iterlen.py index b51263d118a..1770de2c0ad 100644 --- a/Lib/test/test_iterlen.py +++ b/Lib/test/test_iterlen.py @@ -43,12 +43,22 @@ enumerate(iter('abc')). import unittest from test import test_support -from itertools import repeat, count +from itertools import repeat from collections import deque from UserList import UserList +from __builtin__ import len as _len n = 10 +def len(obj): + try: + return _len(obj) + except TypeError: + try: + return obj._length_cue() + except AttributeError: + raise TypeError + class TestInvariantWithoutMutations(unittest.TestCase): def test_invariant(self): diff --git a/Lib/test/test_itertools.py b/Lib/test/test_itertools.py index 5db128cda14..635d1563760 100644 --- a/Lib/test/test_itertools.py +++ b/Lib/test/test_itertools.py @@ -670,6 +670,7 @@ class TestVariousIteratorArgs(unittest.TestCase): class LengthTransparency(unittest.TestCase): def test_repeat(self): + from test.test_iterlen import len self.assertEqual(len(repeat(None, 50)), 50) self.assertRaises(TypeError, len, repeat(None)) diff --git a/Misc/NEWS b/Misc/NEWS index 00bd2471de6..409126aa09c 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -12,6 +12,10 @@ What's New in Python 2.5 alpha 1? Core and builtins ----------------- +- All iterators now have a Boolean value of true. Formerly, some iterators + supported a __len__() method which evaluated to False when the iterator + was empty. + - On 64-bit platforms, when __len__() returns a value that cannot be represented as a C int, raise OverflowError. diff --git a/Modules/collectionsmodule.c b/Modules/collectionsmodule.c index ffe1a96c6a1..1a8258ef7c3 100644 --- a/Modules/collectionsmodule.c +++ b/Modules/collectionsmodule.c @@ -935,15 +935,17 @@ dequeiter_next(dequeiterobject *it) return item; } -static int +static PyObject * dequeiter_len(dequeiterobject *it) { - return it->counter; + return PyInt_FromLong(it->counter); } -static PySequenceMethods dequeiter_as_sequence = { - (inquiry)dequeiter_len, /* sq_length */ - 0, /* sq_concat */ +PyDoc_STRVAR(length_cue_doc, "Private method returning an estimate of len(list(it))."); + +static PyMethodDef dequeiter_methods[] = { + {"_length_cue", (PyCFunction)dequeiter_len, METH_NOARGS, length_cue_doc}, + {NULL, NULL} /* sentinel */ }; PyTypeObject dequeiter_type = { @@ -960,7 +962,7 @@ PyTypeObject dequeiter_type = { 0, /* tp_compare */ 0, /* tp_repr */ 0, /* tp_as_number */ - &dequeiter_as_sequence, /* tp_as_sequence */ + 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ @@ -976,6 +978,7 @@ PyTypeObject dequeiter_type = { 0, /* tp_weaklistoffset */ PyObject_SelfIter, /* tp_iter */ (iternextfunc)dequeiter_next, /* tp_iternext */ + dequeiter_methods, /* tp_methods */ 0, }; @@ -1042,7 +1045,7 @@ PyTypeObject dequereviter_type = { 0, /* tp_compare */ 0, /* tp_repr */ 0, /* tp_as_number */ - &dequeiter_as_sequence, /* tp_as_sequence */ + 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ @@ -1058,6 +1061,7 @@ PyTypeObject dequereviter_type = { 0, /* tp_weaklistoffset */ PyObject_SelfIter, /* tp_iter */ (iternextfunc)dequereviter_next, /* tp_iternext */ + dequeiter_methods, /* tp_methods */ 0, }; diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c index 34b37be43ff..5ec5b8dde9f 100644 --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -2336,17 +2336,21 @@ repeat_repr(repeatobject *ro) return result; } -static int +static PyObject * repeat_len(repeatobject *ro) { - if (ro->cnt == -1) + if (ro->cnt == -1) { PyErr_SetString(PyExc_TypeError, "len() of unsized object"); - return (int)(ro->cnt); + return NULL; + } + return PyInt_FromLong(ro->cnt); } -static PySequenceMethods repeat_as_sequence = { - (inquiry)repeat_len, /* sq_length */ - 0, /* sq_concat */ +PyDoc_STRVAR(length_cue_doc, "Private method returning an estimate of len(list(it))."); + +static PyMethodDef repeat_methods[] = { + {"_length_cue", (PyCFunction)repeat_len, METH_NOARGS, length_cue_doc}, + {NULL, NULL} /* sentinel */ }; PyDoc_STRVAR(repeat_doc, @@ -2368,7 +2372,7 @@ static PyTypeObject repeat_type = { 0, /* tp_compare */ (reprfunc)repeat_repr, /* tp_repr */ 0, /* tp_as_number */ - &repeat_as_sequence, /* tp_as_sequence */ + 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ @@ -2385,7 +2389,7 @@ static PyTypeObject repeat_type = { 0, /* tp_weaklistoffset */ PyObject_SelfIter, /* tp_iter */ (iternextfunc)repeat_next, /* tp_iternext */ - 0, /* tp_methods */ + repeat_methods, /* tp_methods */ 0, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ diff --git a/Objects/abstract.c b/Objects/abstract.c index 94af3da039b..1f8feb52e72 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -81,6 +81,31 @@ PyObject_Length(PyObject *o) } #define PyObject_Length PyObject_Size +int +_PyObject_LengthCue(PyObject *o) +{ + int rv = PyObject_Size(o); + if (rv != -1) + return rv; + if (PyErr_ExceptionMatches(PyExc_TypeError) || + PyErr_ExceptionMatches(PyExc_AttributeError)) { + PyObject *err_type, *err_value, *err_tb, *ro; + + PyErr_Fetch(&err_type, &err_value, &err_tb); + ro = PyObject_CallMethod(o, "_length_cue", NULL); + if (ro != NULL) { + rv = (int)PyInt_AsLong(ro); + Py_DECREF(ro); + Py_XDECREF(err_type); + Py_XDECREF(err_value); + Py_XDECREF(err_tb); + return rv; + } + PyErr_Restore(err_type, err_value, err_tb); + } + return -1; +} + PyObject * PyObject_GetItem(PyObject *o, PyObject *key) { @@ -1399,7 +1424,7 @@ PySequence_Tuple(PyObject *v) return NULL; /* Guess result size and allocate space. */ - n = PyObject_Size(v); + n = _PyObject_LengthCue(v); if (n < 0) { if (!PyErr_ExceptionMatches(PyExc_TypeError) && !PyErr_ExceptionMatches(PyExc_AttributeError)) { diff --git a/Objects/dictobject.c b/Objects/dictobject.c index e90aca4b0fd..42e55e868c2 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -2054,17 +2054,20 @@ dictiter_dealloc(dictiterobject *di) PyObject_Del(di); } -static int +static PyObject * dictiter_len(dictiterobject *di) { + int len = 0; if (di->di_dict != NULL && di->di_used == di->di_dict->ma_used) - return di->len; - return 0; + len = di->len; + return PyInt_FromLong(len); } -static PySequenceMethods dictiter_as_sequence = { - (inquiry)dictiter_len, /* sq_length */ - 0, /* sq_concat */ +PyDoc_STRVAR(length_cue_doc, "Private method returning an estimate of len(list(it))."); + +static PyMethodDef dictiter_methods[] = { + {"_length_cue", (PyCFunction)dictiter_len, METH_NOARGS, length_cue_doc}, + {NULL, NULL} /* sentinel */ }; static PyObject *dictiter_iternextkey(dictiterobject *di) @@ -2120,7 +2123,7 @@ PyTypeObject PyDictIterKey_Type = { 0, /* tp_compare */ 0, /* tp_repr */ 0, /* tp_as_number */ - &dictiter_as_sequence, /* tp_as_sequence */ + 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ @@ -2136,6 +2139,8 @@ PyTypeObject PyDictIterKey_Type = { 0, /* tp_weaklistoffset */ PyObject_SelfIter, /* tp_iter */ (iternextfunc)dictiter_iternextkey, /* tp_iternext */ + dictiter_methods, /* tp_methods */ + 0, }; static PyObject *dictiter_iternextvalue(dictiterobject *di) @@ -2191,7 +2196,7 @@ PyTypeObject PyDictIterValue_Type = { 0, /* tp_compare */ 0, /* tp_repr */ 0, /* tp_as_number */ - &dictiter_as_sequence, /* tp_as_sequence */ + 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ @@ -2207,6 +2212,8 @@ PyTypeObject PyDictIterValue_Type = { 0, /* tp_weaklistoffset */ PyObject_SelfIter, /* tp_iter */ (iternextfunc)dictiter_iternextvalue, /* tp_iternext */ + dictiter_methods, /* tp_methods */ + 0, }; static PyObject *dictiter_iternextitem(dictiterobject *di) @@ -2276,7 +2283,7 @@ PyTypeObject PyDictIterItem_Type = { 0, /* tp_compare */ 0, /* tp_repr */ 0, /* tp_as_number */ - &dictiter_as_sequence, /* tp_as_sequence */ + 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ @@ -2292,4 +2299,6 @@ PyTypeObject PyDictIterItem_Type = { 0, /* tp_weaklistoffset */ PyObject_SelfIter, /* tp_iter */ (iternextfunc)dictiter_iternextitem, /* tp_iternext */ + dictiter_methods, /* tp_methods */ + 0, }; diff --git a/Objects/enumobject.c b/Objects/enumobject.c index aac88dbb012..f74acdcddc9 100644 --- a/Objects/enumobject.c +++ b/Objects/enumobject.c @@ -239,23 +239,25 @@ PyDoc_STRVAR(reversed_doc, "\n" "Return a reverse iterator"); -static int +static PyObject * reversed_len(reversedobject *ro) { int position, seqsize; if (ro->seq == NULL) - return 0; + return PyInt_FromLong(0); seqsize = PySequence_Size(ro->seq); if (seqsize == -1) - return -1; + return NULL; position = ro->index + 1; - return (seqsize < position) ? 0 : position; + return PyInt_FromLong((seqsize < position) ? 0 : position); } -static PySequenceMethods reversed_as_sequence = { - (inquiry)reversed_len, /* sq_length */ - 0, /* sq_concat */ +PyDoc_STRVAR(length_cue_doc, "Private method returning an estimate of len(list(it))."); + +static PyMethodDef reversediter_methods[] = { + {"_length_cue", (PyCFunction)reversed_len, METH_NOARGS, length_cue_doc}, + {NULL, NULL} /* sentinel */ }; PyTypeObject PyReversed_Type = { @@ -272,7 +274,7 @@ PyTypeObject PyReversed_Type = { 0, /* tp_compare */ 0, /* tp_repr */ 0, /* tp_as_number */ - &reversed_as_sequence, /* tp_as_sequence */ + 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ @@ -289,7 +291,7 @@ PyTypeObject PyReversed_Type = { 0, /* tp_weaklistoffset */ PyObject_SelfIter, /* tp_iter */ (iternextfunc)reversed_next, /* tp_iternext */ - 0, /* tp_methods */ + reversediter_methods, /* tp_methods */ 0, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ diff --git a/Objects/iterobject.c b/Objects/iterobject.c index b414cc2e9f4..fdee3ca9178 100644 --- a/Objects/iterobject.c +++ b/Objects/iterobject.c @@ -71,7 +71,7 @@ iter_iternext(PyObject *iterator) return NULL; } -static int +static PyObject * iter_len(seqiterobject *it) { int seqsize, len; @@ -79,17 +79,19 @@ iter_len(seqiterobject *it) if (it->it_seq) { seqsize = PySequence_Size(it->it_seq); if (seqsize == -1) - return -1; + return NULL; len = seqsize - it->it_index; if (len >= 0) - return len; + return PyInt_FromLong(len); } - return 0; + return PyInt_FromLong(0); } -static PySequenceMethods iter_as_sequence = { - (inquiry)iter_len, /* sq_length */ - 0, /* sq_concat */ +PyDoc_STRVAR(length_cue_doc, "Private method returning an estimate of len(list(it))."); + +static PyMethodDef seqiter_methods[] = { + {"_length_cue", (PyCFunction)iter_len, METH_NOARGS, length_cue_doc}, + {NULL, NULL} /* sentinel */ }; PyTypeObject PySeqIter_Type = { @@ -106,7 +108,7 @@ PyTypeObject PySeqIter_Type = { 0, /* tp_compare */ 0, /* tp_repr */ 0, /* tp_as_number */ - &iter_as_sequence, /* tp_as_sequence */ + 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ @@ -122,13 +124,8 @@ PyTypeObject PySeqIter_Type = { 0, /* tp_weaklistoffset */ PyObject_SelfIter, /* tp_iter */ (iternextfunc)iter_iternext, /* tp_iternext */ - 0, /* tp_methods */ + seqiter_methods, /* tp_methods */ 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ }; /* -------------------------------------- */ @@ -236,10 +233,4 @@ PyTypeObject PyCallIter_Type = { PyObject_SelfIter, /* tp_iter */ (iternextfunc)calliter_iternext, /* tp_iternext */ 0, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ }; diff --git a/Objects/listobject.c b/Objects/listobject.c index 3b7358a312e..1a96361526f 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -775,7 +775,7 @@ listextend(PyListObject *self, PyObject *b) iternext = *it->ob_type->tp_iternext; /* Guess a result list size. */ - n = PyObject_Size(b); + n = _PyObject_LengthCue(b); if (n < 0) { if (!PyErr_ExceptionMatches(PyExc_TypeError) && !PyErr_ExceptionMatches(PyExc_AttributeError)) { @@ -2764,21 +2764,23 @@ listiter_next(listiterobject *it) return NULL; } -static int +static PyObject * listiter_len(listiterobject *it) { int len; if (it->it_seq) { len = PyList_GET_SIZE(it->it_seq) - it->it_index; if (len >= 0) - return len; + return PyInt_FromLong((long)len); } - return 0; + return PyInt_FromLong(0); } -static PySequenceMethods listiter_as_sequence = { - (inquiry)listiter_len, /* sq_length */ - 0, /* sq_concat */ +PyDoc_STRVAR(length_cue_doc, "Private method returning an estimate of len(list(it))."); + +static PyMethodDef listiter_methods[] = { + {"_length_cue", (PyCFunction)listiter_len, METH_NOARGS, length_cue_doc}, + {NULL, NULL} /* sentinel */ }; PyTypeObject PyListIter_Type = { @@ -2795,7 +2797,7 @@ PyTypeObject PyListIter_Type = { 0, /* tp_compare */ 0, /* tp_repr */ 0, /* tp_as_number */ - &listiter_as_sequence, /* tp_as_sequence */ + 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ @@ -2811,13 +2813,8 @@ PyTypeObject PyListIter_Type = { 0, /* tp_weaklistoffset */ PyObject_SelfIter, /* tp_iter */ (iternextfunc)listiter_next, /* tp_iternext */ - 0, /* tp_methods */ + listiter_methods, /* tp_methods */ 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ }; /*********************** List Reverse Iterator **************************/ diff --git a/Objects/rangeobject.c b/Objects/rangeobject.c index 8b5650a4fdf..3cc5504631b 100644 --- a/Objects/rangeobject.c +++ b/Objects/rangeobject.c @@ -262,17 +262,18 @@ rangeiter_next(rangeiterobject *r) return NULL; } -static int +static PyObject * rangeiter_len(rangeiterobject *r) { - return r->len - r->index; + return PyInt_FromLong(r->len - r->index); } -static PySequenceMethods rangeiter_as_sequence = { - (inquiry)rangeiter_len, /* sq_length */ - 0, /* sq_concat */ -}; +PyDoc_STRVAR(length_cue_doc, "Private method returning an estimate of len(list(it))."); +static PyMethodDef rangeiter_methods[] = { + {"_length_cue", (PyCFunction)rangeiter_len, METH_NOARGS, length_cue_doc}, + {NULL, NULL} /* sentinel */ +}; static PyTypeObject Pyrangeiter_Type = { PyObject_HEAD_INIT(&PyType_Type) @@ -288,7 +289,7 @@ static PyTypeObject Pyrangeiter_Type = { 0, /* tp_compare */ 0, /* tp_repr */ 0, /* tp_as_number */ - &rangeiter_as_sequence, /* tp_as_sequence */ + 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ @@ -304,5 +305,6 @@ static PyTypeObject Pyrangeiter_Type = { 0, /* tp_weaklistoffset */ PyObject_SelfIter, /* tp_iter */ (iternextfunc)rangeiter_next, /* tp_iternext */ - 0, /* tp_methods */ + rangeiter_methods, /* tp_methods */ + 0, }; diff --git a/Objects/setobject.c b/Objects/setobject.c index c4cd562d582..29a9184c360 100644 --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -749,17 +749,20 @@ setiter_dealloc(setiterobject *si) PyObject_Del(si); } -static int +static PyObject * setiter_len(setiterobject *si) { + int len = 0; if (si->si_set != NULL && si->si_used == si->si_set->used) - return si->len; - return 0; + len = si->len; + return PyInt_FromLong(len); } -static PySequenceMethods setiter_as_sequence = { - (inquiry)setiter_len, /* sq_length */ - 0, /* sq_concat */ +PyDoc_STRVAR(length_cue_doc, "Private method returning an estimate of len(list(it))."); + +static PyMethodDef setiter_methods[] = { + {"_length_cue", (PyCFunction)setiter_len, METH_NOARGS, length_cue_doc}, + {NULL, NULL} /* sentinel */ }; static PyObject *setiter_iternext(setiterobject *si) @@ -814,7 +817,7 @@ static PyTypeObject PySetIter_Type = { 0, /* tp_compare */ 0, /* tp_repr */ 0, /* tp_as_number */ - &setiter_as_sequence, /* tp_as_sequence */ + 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ @@ -830,6 +833,8 @@ static PyTypeObject PySetIter_Type = { 0, /* tp_weaklistoffset */ PyObject_SelfIter, /* tp_iter */ (iternextfunc)setiter_iternext, /* tp_iternext */ + setiter_methods, /* tp_methods */ + 0, }; static int diff --git a/Objects/tupleobject.c b/Objects/tupleobject.c index ea7d7530223..76e5de32d18 100644 --- a/Objects/tupleobject.c +++ b/Objects/tupleobject.c @@ -851,17 +851,20 @@ tupleiter_next(tupleiterobject *it) return NULL; } -static int +static PyObject * tupleiter_len(tupleiterobject *it) { + int len = 0; if (it->it_seq) - return PyTuple_GET_SIZE(it->it_seq) - it->it_index; - return 0; + len = PyTuple_GET_SIZE(it->it_seq) - it->it_index; + return PyInt_FromLong(len); } -static PySequenceMethods tupleiter_as_sequence = { - (inquiry)tupleiter_len, /* sq_length */ - 0, /* sq_concat */ +PyDoc_STRVAR(length_cue_doc, "Private method returning an estimate of len(list(it))."); + +static PyMethodDef tupleiter_methods[] = { + {"_length_cue", (PyCFunction)tupleiter_len, METH_NOARGS, length_cue_doc}, + {NULL, NULL} /* sentinel */ }; PyTypeObject PyTupleIter_Type = { @@ -878,7 +881,7 @@ PyTypeObject PyTupleIter_Type = { 0, /* tp_compare */ 0, /* tp_repr */ 0, /* tp_as_number */ - &tupleiter_as_sequence, /* tp_as_sequence */ + 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ @@ -894,4 +897,6 @@ PyTypeObject PyTupleIter_Type = { 0, /* tp_weaklistoffset */ PyObject_SelfIter, /* tp_iter */ (iternextfunc)tupleiter_next, /* tp_iternext */ + tupleiter_methods, /* tp_methods */ + 0, }; diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index dca8555a2fb..3e5f4ebfefa 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -221,7 +221,7 @@ builtin_filter(PyObject *self, PyObject *args) goto Fail_arg; /* Guess a result list size. */ - len = PyObject_Size(seq); + len = _PyObject_LengthCue(seq); if (len < 0) { if (!PyErr_ExceptionMatches(PyExc_TypeError) && !PyErr_ExceptionMatches(PyExc_AttributeError)) { @@ -873,7 +873,7 @@ builtin_map(PyObject *self, PyObject *args) } /* Update len. */ - curlen = PyObject_Size(curseq); + curlen = _PyObject_LengthCue(curseq); if (curlen < 0) { if (!PyErr_ExceptionMatches(PyExc_TypeError) && !PyErr_ExceptionMatches(PyExc_AttributeError)) { @@ -2108,7 +2108,7 @@ builtin_zip(PyObject *self, PyObject *args) len = -1; /* unknown */ for (i = 0; i < itemsize; ++i) { PyObject *item = PyTuple_GET_ITEM(args, i); - int thislen = PyObject_Size(item); + int thislen = _PyObject_LengthCue(item); if (thislen < 0) { if (!PyErr_ExceptionMatches(PyExc_TypeError) && !PyErr_ExceptionMatches(PyExc_AttributeError)) {