summaryrefslogtreecommitdiffstats
path: root/Objects/abstract.c
diff options
context:
space:
mode:
authorTim Peters <tim.peters@gmail.com>2001-05-05 10:06:17 (GMT)
committerTim Peters <tim.peters@gmail.com>2001-05-05 10:06:17 (GMT)
commitde9725f1352856b7d6de1bb29383a7be5f181740 (patch)
tree3fff3245c5dff4684440f7e9227c34bed9ef27b5 /Objects/abstract.c
parent2cfe36828342e16cd274b968736a01aed5c49557 (diff)
downloadcpython-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.c63
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 */