Implement __contains__ for dict_keys and dict_items.
(Not for dict_values, where it can't be done faster than the default implementation which just iterates the elements.)
This commit is contained in:
parent
83825acd1b
commit
3ac6741f79
@ -3,17 +3,39 @@ from test import test_support
|
|||||||
|
|
||||||
class DictSetTest(unittest.TestCase):
|
class DictSetTest(unittest.TestCase):
|
||||||
|
|
||||||
|
def test_constructors_not_callable(self):
|
||||||
|
kt = type({}.KEYS())
|
||||||
|
self.assertRaises(TypeError, kt, {})
|
||||||
|
self.assertRaises(TypeError, kt)
|
||||||
|
it = type({}.ITEMS())
|
||||||
|
self.assertRaises(TypeError, it, {})
|
||||||
|
self.assertRaises(TypeError, it)
|
||||||
|
vt = type({}.VALUES())
|
||||||
|
self.assertRaises(TypeError, vt, {})
|
||||||
|
self.assertRaises(TypeError, vt)
|
||||||
|
|
||||||
def test_dict_keys(self):
|
def test_dict_keys(self):
|
||||||
d = {1: 10, "a": "ABC"}
|
d = {1: 10, "a": "ABC"}
|
||||||
keys = d.KEYS()
|
keys = d.KEYS()
|
||||||
self.assertEqual(set(keys), {1, "a"})
|
self.assertEqual(set(keys), {1, "a"})
|
||||||
self.assertEqual(len(keys), 2)
|
self.assertEqual(len(keys), 2)
|
||||||
|
self.assert_(1 in keys)
|
||||||
|
self.assert_("a" in keys)
|
||||||
|
self.assert_(10 not in keys)
|
||||||
|
self.assert_("Z" not in keys)
|
||||||
|
|
||||||
def test_dict_items(self):
|
def test_dict_items(self):
|
||||||
d = {1: 10, "a": "ABC"}
|
d = {1: 10, "a": "ABC"}
|
||||||
items = d.ITEMS()
|
items = d.ITEMS()
|
||||||
self.assertEqual(set(items), {(1, 10), ("a", "ABC")})
|
self.assertEqual(set(items), {(1, 10), ("a", "ABC")})
|
||||||
self.assertEqual(len(items), 2)
|
self.assertEqual(len(items), 2)
|
||||||
|
self.assert_((1, 10) in items)
|
||||||
|
self.assert_(("a", "ABC") in items)
|
||||||
|
self.assert_((1, 11) not in items)
|
||||||
|
self.assert_(1 not in items)
|
||||||
|
self.assert_(() not in items)
|
||||||
|
self.assert_((1,) not in items)
|
||||||
|
self.assert_((1, 2, 3) not in items)
|
||||||
|
|
||||||
def test_dict_values(self):
|
def test_dict_values(self):
|
||||||
d = {1: 10, "a": "ABC"}
|
d = {1: 10, "a": "ABC"}
|
||||||
|
@ -2336,37 +2336,40 @@ PyTypeObject PyDictIterItem_Type = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************************/
|
||||||
/* View objects for keys(), items(), values(). */
|
/* View objects for keys(), items(), values(). */
|
||||||
|
/***********************************************/
|
||||||
|
|
||||||
/* While this is incomplete, we use KEYS(), ITEMS(), VALUES(). */
|
/* While this is incomplete, we use KEYS(), ITEMS(), VALUES(). */
|
||||||
|
|
||||||
/* The instance lay-out is the same for all three; but the type differs. */
|
/* The instance lay-out is the same for all three; but the type differs. */
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
PyObject_HEAD
|
PyObject_HEAD
|
||||||
dictobject *ds_dict;
|
dictobject *dv_dict;
|
||||||
} dictviewobject;
|
} dictviewobject;
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
dictview_dealloc(dictviewobject *ds)
|
dictview_dealloc(dictviewobject *dv)
|
||||||
{
|
{
|
||||||
Py_XDECREF(ds->ds_dict);
|
Py_XDECREF(dv->dv_dict);
|
||||||
PyObject_Del(ds);
|
PyObject_Del(dv);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Py_ssize_t
|
static Py_ssize_t
|
||||||
dictview_len(dictviewobject *ds)
|
dictview_len(dictviewobject *dv)
|
||||||
{
|
{
|
||||||
Py_ssize_t len = 0;
|
Py_ssize_t len = 0;
|
||||||
if (ds->ds_dict != NULL)
|
if (dv->dv_dict != NULL)
|
||||||
len = ds->ds_dict->ma_used;
|
len = dv->dv_dict->ma_used;
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
dictview_new(PyObject *dict, PyTypeObject *type)
|
dictview_new(PyObject *dict, PyTypeObject *type)
|
||||||
{
|
{
|
||||||
dictviewobject *ds;
|
dictviewobject *dv;
|
||||||
if (dict == NULL) {
|
if (dict == NULL) {
|
||||||
PyErr_BadInternalCall();
|
PyErr_BadInternalCall();
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -2378,23 +2381,31 @@ dictview_new(PyObject *dict, PyTypeObject *type)
|
|||||||
type->tp_name, dict->ob_type->tp_name);
|
type->tp_name, dict->ob_type->tp_name);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
ds = PyObject_New(dictviewobject, type);
|
dv = PyObject_New(dictviewobject, type);
|
||||||
if (ds == NULL)
|
if (dv == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
Py_INCREF(dict);
|
Py_INCREF(dict);
|
||||||
ds->ds_dict = (dictobject *)dict;
|
dv->dv_dict = (dictobject *)dict;
|
||||||
return (PyObject *)ds;
|
return (PyObject *)dv;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* dict_keys */
|
/*** dict_keys ***/
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
dictkeys_iter(dictviewobject *ds)
|
dictkeys_iter(dictviewobject *dv)
|
||||||
{
|
{
|
||||||
if (ds->ds_dict == NULL) {
|
if (dv->dv_dict == NULL) {
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
return dictiter_new(ds->ds_dict, &PyDictIterKey_Type);
|
return dictiter_new(dv->dv_dict, &PyDictIterKey_Type);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
dictkeys_contains(dictviewobject *dv, PyObject *obj)
|
||||||
|
{
|
||||||
|
if (dv->dv_dict == NULL)
|
||||||
|
return 0;
|
||||||
|
return PyDict_Contains((PyObject *)dv->dv_dict, obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
static PySequenceMethods dictkeys_as_sequence = {
|
static PySequenceMethods dictkeys_as_sequence = {
|
||||||
@ -2405,7 +2416,7 @@ static PySequenceMethods dictkeys_as_sequence = {
|
|||||||
0, /* sq_slice */
|
0, /* sq_slice */
|
||||||
0, /* sq_ass_item */
|
0, /* sq_ass_item */
|
||||||
0, /* sq_ass_slice */
|
0, /* sq_ass_slice */
|
||||||
(objobjproc)0, /* sq_contains */
|
(objobjproc)dictkeys_contains, /* sq_contains */
|
||||||
};
|
};
|
||||||
|
|
||||||
static PyMethodDef dictkeys_methods[] = {
|
static PyMethodDef dictkeys_methods[] = {
|
||||||
@ -2452,15 +2463,34 @@ dictkeys_new(PyObject *dict)
|
|||||||
return dictview_new(dict, &PyDictKeys_Type);
|
return dictview_new(dict, &PyDictKeys_Type);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* dict_items */
|
/*** dict_items ***/
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
dictitems_iter(dictviewobject *ds)
|
dictitems_iter(dictviewobject *dv)
|
||||||
{
|
{
|
||||||
if (ds->ds_dict == NULL) {
|
if (dv->dv_dict == NULL) {
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
return dictiter_new(ds->ds_dict, &PyDictIterItem_Type);
|
return dictiter_new(dv->dv_dict, &PyDictIterItem_Type);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
dictitems_contains(dictviewobject *dv, PyObject *obj)
|
||||||
|
{
|
||||||
|
PyObject *key, *value, *found;
|
||||||
|
if (dv->dv_dict == NULL)
|
||||||
|
return 0;
|
||||||
|
if (!PyTuple_Check(obj) || PyTuple_GET_SIZE(obj) != 2)
|
||||||
|
return 0;
|
||||||
|
key = PyTuple_GET_ITEM(obj, 0);
|
||||||
|
value = PyTuple_GET_ITEM(obj, 1);
|
||||||
|
found = PyDict_GetItem((PyObject *)dv->dv_dict, key);
|
||||||
|
if (found == NULL) {
|
||||||
|
if (PyErr_Occurred())
|
||||||
|
return -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return PyObject_RichCompareBool(value, found, Py_EQ);
|
||||||
}
|
}
|
||||||
|
|
||||||
static PySequenceMethods dictitems_as_sequence = {
|
static PySequenceMethods dictitems_as_sequence = {
|
||||||
@ -2471,7 +2501,7 @@ static PySequenceMethods dictitems_as_sequence = {
|
|||||||
0, /* sq_slice */
|
0, /* sq_slice */
|
||||||
0, /* sq_ass_item */
|
0, /* sq_ass_item */
|
||||||
0, /* sq_ass_slice */
|
0, /* sq_ass_slice */
|
||||||
(objobjproc)0, /* sq_contains */
|
(objobjproc)dictitems_contains, /* sq_contains */
|
||||||
};
|
};
|
||||||
|
|
||||||
static PyMethodDef dictitems_methods[] = {
|
static PyMethodDef dictitems_methods[] = {
|
||||||
@ -2518,15 +2548,15 @@ dictitems_new(PyObject *dict)
|
|||||||
return dictview_new(dict, &PyDictItems_Type);
|
return dictview_new(dict, &PyDictItems_Type);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* dict_values */
|
/*** dict_values ***/
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
dictvalues_iter(dictviewobject *ds)
|
dictvalues_iter(dictviewobject *dv)
|
||||||
{
|
{
|
||||||
if (ds->ds_dict == NULL) {
|
if (dv->dv_dict == NULL) {
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
return dictiter_new(ds->ds_dict, &PyDictIterValue_Type);
|
return dictiter_new(dv->dv_dict, &PyDictIterValue_Type);
|
||||||
}
|
}
|
||||||
|
|
||||||
static PySequenceMethods dictvalues_as_sequence = {
|
static PySequenceMethods dictvalues_as_sequence = {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user