diff --git a/Objects/abstract.c b/Objects/abstract.c --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -81,17 +81,36 @@ PyObject_LengthHint(PyObject *o, Py_ssiz { PyObject *hint, *result; Py_ssize_t res; + PySequenceMethods *seq; + PyMappingMethods *map; _Py_IDENTIFIER(__length_hint__); - res = PyObject_Length(o); - if (res < 0 && PyErr_Occurred()) { - if (!PyErr_ExceptionMatches(PyExc_TypeError)) { + + if (o == NULL) { + null_error(); + return -1; + } + + seq = o->ob_type->tp_as_sequence; + if (seq && seq->sq_length) { + res = seq->sq_length(o); + if (res >= 0) + return res; + else if (PyErr_Occurred() && + !PyErr_ExceptionMatches(PyExc_TypeError)) return -1; - } PyErr_Clear(); } - else { - return res; + map = o->ob_type->tp_as_mapping; + if (map && map->mp_length) { + res = map->mp_length(o); + if (res >= 0) + return res; + else if (PyErr_Occurred() && + !PyErr_ExceptionMatches(PyExc_TypeError)) + return -1; + PyErr_Clear(); } + hint = _PyObject_LookupSpecial(o, &PyId___length_hint__); if (hint == NULL) { if (PyErr_Occurred()) {