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.
diff --git a/Objects/abstract.c b/Objects/abstract.c
index 1cb4ef8..4c8ef83 100644
--- a/Objects/abstract.c
+++ b/Objects/abstract.c
@@ -82,29 +82,47 @@
 }
 #define PyObject_Length PyObject_Size
 
-Py_ssize_t
-_PyObject_LengthHint(PyObject *o)
-{
-	Py_ssize_t 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_hint__", NULL);
-		if (ro != NULL) {
-			rv = 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);
+/* 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
+_PyObject_LengthHint(PyObject *o, Py_ssize_t defaultvalue)
+{
+	static PyObject *hintstrobj = NULL;
+	PyObject *ro;
+	Py_ssize_t rv;
+
+	/* try o.__len__() */
+	rv = PyObject_Size(o);
+	if (rv >= 0)
+		return rv;
+	if (PyErr_Occurred())
+		PyErr_Clear();
+
+	/* cache a hashed version of the attribute string */
+	if (hintstrobj == NULL) {
+		hintstrobj = PyString_InternFromString("__length_hint__");
+		if (hintstrobj == NULL)
+			goto defaultcase;
 	}
-	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 *
@@ -1505,17 +1523,7 @@
 		return NULL;
 
 	/* Guess result size and allocate space. */
-	n = _PyObject_LengthHint(v);
-	if (n < 0) {
-		if (PyErr_Occurred()
-		    && !PyErr_ExceptionMatches(PyExc_TypeError)
-		    && !PyErr_ExceptionMatches(PyExc_AttributeError)) {
-			Py_DECREF(it);
-			return NULL;
-		}
-		PyErr_Clear();
-		n = 10;  /* arbitrary */
-	}
+	n = _PyObject_LengthHint(v, 10);
 	result = PyTuple_New(n);
 	if (result == NULL)
 		goto Fail;
diff --git a/Objects/listobject.c b/Objects/listobject.c
index 8389a86..ca767da 100644
--- a/Objects/listobject.c
+++ b/Objects/listobject.c
@@ -794,17 +794,7 @@
 	iternext = *it->ob_type->tp_iternext;
 
 	/* Guess a result list size. */
-	n = _PyObject_LengthHint(b);
-	if (n < 0) {
-		if (PyErr_Occurred()
-		    && !PyErr_ExceptionMatches(PyExc_TypeError)
-		    && !PyErr_ExceptionMatches(PyExc_AttributeError)) {
-			Py_DECREF(it);
-			return NULL;
-		}
-		PyErr_Clear();
-		n = 8;	/* arbitrary */
-	}
+	n = _PyObject_LengthHint(b, 8);
 	m = Py_Size(self);
 	mn = m + n;
 	if (mn >= m) {