diff options
author | Tim Peters <tim.peters@gmail.com> | 2001-05-05 10:06:17 (GMT) |
---|---|---|
committer | Tim Peters <tim.peters@gmail.com> | 2001-05-05 10:06:17 (GMT) |
commit | de9725f1352856b7d6de1bb29383a7be5f181740 (patch) | |
tree | 3fff3245c5dff4684440f7e9227c34bed9ef27b5 /Objects/abstract.c | |
parent | 2cfe36828342e16cd274b968736a01aed5c49557 (diff) | |
download | cpython-de9725f1352856b7d6de1bb29383a7be5f181740.zip cpython-de9725f1352856b7d6de1bb29383a7be5f181740.tar.gz cpython-de9725f1352856b7d6de1bb29383a7be5f181740.tar.bz2 |
Make 'x in y' and 'x not in y' (PySequence_Contains) play nice w/ iterators.
NEEDS DOC CHANGES
A few more AttributeErrors turned into TypeErrors, but in test_contains
this time.
The full story for instance objects is pretty much unexplainable, because
instance_contains() tries its own flavor of iteration-based containment
testing first, and PySequence_Contains doesn't get a chance at it unless
instance_contains() blows up. A consequence is that
some_complex_number in some_instance
dies with a TypeError unless some_instance.__class__ defines __iter__ but
does not define __getitem__.
Diffstat (limited to 'Objects/abstract.c')
-rw-r--r-- | Objects/abstract.c | 63 |
1 files changed, 34 insertions, 29 deletions
diff --git a/Objects/abstract.c b/Objects/abstract.c index 30e6191..a0a40e8 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -1363,46 +1363,51 @@ PySequence_Count(PyObject *s, PyObject *o) return n; } +/* Return -1 if error; 1 if v in w; 0 if v not in w. */ int PySequence_Contains(PyObject *w, PyObject *v) /* v in w */ { - int i, cmp; - PyObject *x; - PySequenceMethods *sq; - - if(PyType_HasFeature(w->ob_type, Py_TPFLAGS_HAVE_SEQUENCE_IN)) { - sq = w->ob_type->tp_as_sequence; - if(sq != NULL && sq->sq_contains != NULL) - return (*sq->sq_contains)(w, v); + PyObject *it; /* iter(w) */ + int result; + + if (PyType_HasFeature(w->ob_type, Py_TPFLAGS_HAVE_SEQUENCE_IN)) { + PySequenceMethods *sq = w->ob_type->tp_as_sequence; + if (sq != NULL && sq->sq_contains != NULL) { + result = (*sq->sq_contains)(w, v); + if (result >= 0) + return result; + assert(PyErr_Occurred()); + if (PyErr_ExceptionMatches(PyExc_AttributeError)) + PyErr_Clear(); + else + return result; + } } - /* If there is no better way to check whether an item is is contained, - do it the hard way */ - sq = w->ob_type->tp_as_sequence; - if (sq == NULL || sq->sq_item == NULL) { + /* Try exhaustive iteration. */ + it = PyObject_GetIter(w); + if (it == NULL) { PyErr_SetString(PyExc_TypeError, - "'in' or 'not in' needs sequence right argument"); + "'in' or 'not in' needs iterable right argument"); return -1; } - for (i = 0; ; i++) { - x = (*sq->sq_item)(w, i); - if (x == NULL) { - if (PyErr_ExceptionMatches(PyExc_IndexError)) { - PyErr_Clear(); - break; - } - return -1; + for (;;) { + int cmp; + PyObject *item = PyIter_Next(it); + if (item == NULL) { + result = PyErr_Occurred() ? -1 : 0; + break; } - cmp = PyObject_RichCompareBool(v, x, Py_EQ); - Py_XDECREF(x); - if (cmp > 0) - return 1; - if (cmp < 0) - return -1; + cmp = PyObject_RichCompareBool(v, item, Py_EQ); + Py_DECREF(item); + if (cmp == 0) + continue; + result = cmp > 0 ? 1 : -1; + break; } - - return 0; + Py_DECREF(it); + return result; } /* Backwards compatibility */ |