Kaydet (Commit) 4e2f7140 authored tarafından Raymond Hettinger's avatar Raymond Hettinger

Fix Issue 1045.

Factor-out common calling code by simplifying the length_hint API.
Speed-up the function by caching the PyObject_String for the attribute lookup.
üst 923ad7a9
...@@ -433,25 +433,12 @@ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx*/ ...@@ -433,25 +433,12 @@ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx*/
PyAPI_FUNC(Py_ssize_t) PyObject_Length(PyObject *o); PyAPI_FUNC(Py_ssize_t) PyObject_Length(PyObject *o);
#define PyObject_Length PyObject_Size #define PyObject_Length PyObject_Size
PyAPI_FUNC(Py_ssize_t) _PyObject_LengthHint(PyObject *o); PyAPI_FUNC(Py_ssize_t) _PyObject_LengthHint(PyObject *o, Py_ssize_t);
/* /*
Return the size of object o. If the object, o, provides Guess the size of object o using len(o) or o.__length_hint__().
both sequence and mapping protocols, the sequence size is If neither of those return a non-negative value, then return the
returned. On error, -1 is returned. If the object provides default value. This function never fails. All exceptions are cleared.
a __length_hint__() method, its value is returned. This is an
internal undocumented API provided for performance reasons;
for compatibility, don't use it outside the core. This is the
equivalent to the Python expression:
try:
return len(o)
except (AttributeError, TypeError):
exc_type, exc_value, exc_tb = sys.exc_info()
try:
return o.__length_hint__()
except:
pass
raise exc_type, exc_value, exc_tb
*/ */
PyAPI_FUNC(PyObject *) PyObject_GetItem(PyObject *o, PyObject *key); PyAPI_FUNC(PyObject *) PyObject_GetItem(PyObject *o, PyObject *key);
......
...@@ -523,7 +523,5 @@ class CommonTest(seq_tests.CommonTest): ...@@ -523,7 +523,5 @@ class CommonTest(seq_tests.CommonTest):
# Bug #1242657 # Bug #1242657
class F(object): class F(object):
def __iter__(self): def __iter__(self):
yield 23
def __len__(self):
raise KeyboardInterrupt raise KeyboardInterrupt
self.assertRaises(KeyboardInterrupt, list, F()) self.assertRaises(KeyboardInterrupt, list, F())
...@@ -82,29 +82,47 @@ PyObject_Length(PyObject *o) ...@@ -82,29 +82,47 @@ PyObject_Length(PyObject *o)
} }
#define PyObject_Length PyObject_Size #define PyObject_Length PyObject_Size
/* The length hint function returns a non-negative value from o.__len__()
or o.__length_hint__(). If those methods aren't found or return a negative
value, then the defaultvalue is returned. This function never fails.
Accordingly, it will mask exceptions raised in either method.
*/
Py_ssize_t Py_ssize_t
_PyObject_LengthHint(PyObject *o) _PyObject_LengthHint(PyObject *o, Py_ssize_t defaultvalue)
{ {
Py_ssize_t rv = PyObject_Size(o); static PyObject *hintstrobj = NULL;
if (rv != -1) PyObject *ro;
Py_ssize_t rv;
/* try o.__len__() */
rv = PyObject_Size(o);
if (rv >= 0)
return rv; return rv;
if (PyErr_ExceptionMatches(PyExc_TypeError) || if (PyErr_Occurred())
PyErr_ExceptionMatches(PyExc_AttributeError)) { PyErr_Clear();
PyObject *err_type, *err_value, *err_tb, *ro;
/* cache a hashed version of the attribute string */
PyErr_Fetch(&err_type, &err_value, &err_tb); if (hintstrobj == NULL) {
ro = PyObject_CallMethod(o, "__length_hint__", NULL); hintstrobj = PyString_InternFromString("__length_hint__");
if (ro != NULL) { if (hintstrobj == NULL)
rv = PyInt_AsLong(ro); goto defaultcase;
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;
/* try o.__length_hint__() */
ro = PyObject_CallMethodObjArgs(o, hintstrobj, NULL);
if (ro == NULL)
goto defaultcase;
rv = PyInt_AsLong(ro);
Py_DECREF(ro);
if (rv >= 0)
return rv;
defaultcase:
if (PyErr_Occurred())
PyErr_Clear();
return defaultvalue;
} }
PyObject * PyObject *
...@@ -1505,17 +1523,7 @@ PySequence_Tuple(PyObject *v) ...@@ -1505,17 +1523,7 @@ PySequence_Tuple(PyObject *v)
return NULL; return NULL;
/* Guess result size and allocate space. */ /* Guess result size and allocate space. */
n = _PyObject_LengthHint(v); n = _PyObject_LengthHint(v, 10);
if (n < 0) {
if (PyErr_Occurred()
&& !PyErr_ExceptionMatches(PyExc_TypeError)
&& !PyErr_ExceptionMatches(PyExc_AttributeError)) {
Py_DECREF(it);
return NULL;
}
PyErr_Clear();
n = 10; /* arbitrary */
}
result = PyTuple_New(n); result = PyTuple_New(n);
if (result == NULL) if (result == NULL)
goto Fail; goto Fail;
......
...@@ -794,17 +794,7 @@ listextend(PyListObject *self, PyObject *b) ...@@ -794,17 +794,7 @@ listextend(PyListObject *self, PyObject *b)
iternext = *it->ob_type->tp_iternext; iternext = *it->ob_type->tp_iternext;
/* Guess a result list size. */ /* Guess a result list size. */
n = _PyObject_LengthHint(b); n = _PyObject_LengthHint(b, 8);
if (n < 0) {
if (PyErr_Occurred()
&& !PyErr_ExceptionMatches(PyExc_TypeError)
&& !PyErr_ExceptionMatches(PyExc_AttributeError)) {
Py_DECREF(it);
return NULL;
}
PyErr_Clear();
n = 8; /* arbitrary */
}
m = Py_Size(self); m = Py_Size(self);
mn = m + n; mn = m + n;
if (mn >= m) { if (mn >= m) {
......
...@@ -236,15 +236,7 @@ builtin_filter(PyObject *self, PyObject *args) ...@@ -236,15 +236,7 @@ builtin_filter(PyObject *self, PyObject *args)
goto Fail_arg; goto Fail_arg;
/* Guess a result list size. */ /* Guess a result list size. */
len = _PyObject_LengthHint(seq); len = _PyObject_LengthHint(seq, 8);
if (len < 0) {
if (!PyErr_ExceptionMatches(PyExc_TypeError) &&
!PyErr_ExceptionMatches(PyExc_AttributeError)) {
goto Fail_it;
}
PyErr_Clear();
len = 8; /* arbitrary */
}
/* Get a result list. */ /* Get a result list. */
if (PyList_Check(seq) && seq->ob_refcnt == 1) { if (PyList_Check(seq) && seq->ob_refcnt == 1) {
...@@ -905,15 +897,7 @@ builtin_map(PyObject *self, PyObject *args) ...@@ -905,15 +897,7 @@ builtin_map(PyObject *self, PyObject *args)
} }
/* Update len. */ /* Update len. */
curlen = _PyObject_LengthHint(curseq); curlen = _PyObject_LengthHint(curseq, 8);
if (curlen < 0) {
if (!PyErr_ExceptionMatches(PyExc_TypeError) &&
!PyErr_ExceptionMatches(PyExc_AttributeError)) {
goto Fail_2;
}
PyErr_Clear();
curlen = 8; /* arbitrary */
}
if (curlen > len) if (curlen > len)
len = curlen; len = curlen;
} }
...@@ -2243,13 +2227,8 @@ builtin_zip(PyObject *self, PyObject *args) ...@@ -2243,13 +2227,8 @@ builtin_zip(PyObject *self, PyObject *args)
len = -1; /* unknown */ len = -1; /* unknown */
for (i = 0; i < itemsize; ++i) { for (i = 0; i < itemsize; ++i) {
PyObject *item = PyTuple_GET_ITEM(args, i); PyObject *item = PyTuple_GET_ITEM(args, i);
Py_ssize_t thislen = _PyObject_LengthHint(item); Py_ssize_t thislen = _PyObject_LengthHint(item, -1);
if (thislen < 0) { if (thislen < 0) {
if (!PyErr_ExceptionMatches(PyExc_TypeError) &&
!PyErr_ExceptionMatches(PyExc_AttributeError)) {
return NULL;
}
PyErr_Clear();
len = -1; len = -1;
break; break;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment