Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 3ac6741

Browse files
committed
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.)
1 parent 83825ac commit 3ac6741

2 files changed

Lines changed: 78 additions & 26 deletions

File tree

Lib/test/test_dictviews.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,39 @@
33

44
class DictSetTest(unittest.TestCase):
55

6+
def test_constructors_not_callable(self):
7+
kt = type({}.KEYS())
8+
self.assertRaises(TypeError, kt, {})
9+
self.assertRaises(TypeError, kt)
10+
it = type({}.ITEMS())
11+
self.assertRaises(TypeError, it, {})
12+
self.assertRaises(TypeError, it)
13+
vt = type({}.VALUES())
14+
self.assertRaises(TypeError, vt, {})
15+
self.assertRaises(TypeError, vt)
16+
617
def test_dict_keys(self):
718
d = {1: 10, "a": "ABC"}
819
keys = d.KEYS()
920
self.assertEqual(set(keys), {1, "a"})
1021
self.assertEqual(len(keys), 2)
22+
self.assert_(1 in keys)
23+
self.assert_("a" in keys)
24+
self.assert_(10 not in keys)
25+
self.assert_("Z" not in keys)
1126

1227
def test_dict_items(self):
1328
d = {1: 10, "a": "ABC"}
1429
items = d.ITEMS()
1530
self.assertEqual(set(items), {(1, 10), ("a", "ABC")})
1631
self.assertEqual(len(items), 2)
32+
self.assert_((1, 10) in items)
33+
self.assert_(("a", "ABC") in items)
34+
self.assert_((1, 11) not in items)
35+
self.assert_(1 not in items)
36+
self.assert_(() not in items)
37+
self.assert_((1,) not in items)
38+
self.assert_((1, 2, 3) not in items)
1739

1840
def test_dict_values(self):
1941
d = {1: 10, "a": "ABC"}

Objects/dictobject.c

Lines changed: 56 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2336,37 +2336,40 @@ PyTypeObject PyDictIterItem_Type = {
23362336
};
23372337

23382338

2339+
/***********************************************/
23392340
/* View objects for keys(), items(), values(). */
2341+
/***********************************************/
2342+
23402343
/* While this is incomplete, we use KEYS(), ITEMS(), VALUES(). */
23412344

23422345
/* The instance lay-out is the same for all three; but the type differs. */
23432346

23442347
typedef struct {
23452348
PyObject_HEAD
2346-
dictobject *ds_dict;
2349+
dictobject *dv_dict;
23472350
} dictviewobject;
23482351

23492352

23502353
static void
2351-
dictview_dealloc(dictviewobject *ds)
2354+
dictview_dealloc(dictviewobject *dv)
23522355
{
2353-
Py_XDECREF(ds->ds_dict);
2354-
PyObject_Del(ds);
2356+
Py_XDECREF(dv->dv_dict);
2357+
PyObject_Del(dv);
23552358
}
23562359

23572360
static Py_ssize_t
2358-
dictview_len(dictviewobject *ds)
2361+
dictview_len(dictviewobject *dv)
23592362
{
23602363
Py_ssize_t len = 0;
2361-
if (ds->ds_dict != NULL)
2362-
len = ds->ds_dict->ma_used;
2364+
if (dv->dv_dict != NULL)
2365+
len = dv->dv_dict->ma_used;
23632366
return len;
23642367
}
23652368

23662369
static PyObject *
23672370
dictview_new(PyObject *dict, PyTypeObject *type)
23682371
{
2369-
dictviewobject *ds;
2372+
dictviewobject *dv;
23702373
if (dict == NULL) {
23712374
PyErr_BadInternalCall();
23722375
return NULL;
@@ -2378,23 +2381,31 @@ dictview_new(PyObject *dict, PyTypeObject *type)
23782381
type->tp_name, dict->ob_type->tp_name);
23792382
return NULL;
23802383
}
2381-
ds = PyObject_New(dictviewobject, type);
2382-
if (ds == NULL)
2384+
dv = PyObject_New(dictviewobject, type);
2385+
if (dv == NULL)
23832386
return NULL;
23842387
Py_INCREF(dict);
2385-
ds->ds_dict = (dictobject *)dict;
2386-
return (PyObject *)ds;
2388+
dv->dv_dict = (dictobject *)dict;
2389+
return (PyObject *)dv;
23872390
}
23882391

2389-
/* dict_keys */
2392+
/*** dict_keys ***/
23902393

23912394
static PyObject *
2392-
dictkeys_iter(dictviewobject *ds)
2395+
dictkeys_iter(dictviewobject *dv)
23932396
{
2394-
if (ds->ds_dict == NULL) {
2397+
if (dv->dv_dict == NULL) {
23952398
Py_RETURN_NONE;
23962399
}
2397-
return dictiter_new(ds->ds_dict, &PyDictIterKey_Type);
2400+
return dictiter_new(dv->dv_dict, &PyDictIterKey_Type);
2401+
}
2402+
2403+
static int
2404+
dictkeys_contains(dictviewobject *dv, PyObject *obj)
2405+
{
2406+
if (dv->dv_dict == NULL)
2407+
return 0;
2408+
return PyDict_Contains((PyObject *)dv->dv_dict, obj);
23982409
}
23992410

24002411
static PySequenceMethods dictkeys_as_sequence = {
@@ -2405,7 +2416,7 @@ static PySequenceMethods dictkeys_as_sequence = {
24052416
0, /* sq_slice */
24062417
0, /* sq_ass_item */
24072418
0, /* sq_ass_slice */
2408-
(objobjproc)0, /* sq_contains */
2419+
(objobjproc)dictkeys_contains, /* sq_contains */
24092420
};
24102421

24112422
static PyMethodDef dictkeys_methods[] = {
@@ -2452,15 +2463,34 @@ dictkeys_new(PyObject *dict)
24522463
return dictview_new(dict, &PyDictKeys_Type);
24532464
}
24542465

2455-
/* dict_items */
2466+
/*** dict_items ***/
24562467

24572468
static PyObject *
2458-
dictitems_iter(dictviewobject *ds)
2469+
dictitems_iter(dictviewobject *dv)
24592470
{
2460-
if (ds->ds_dict == NULL) {
2471+
if (dv->dv_dict == NULL) {
24612472
Py_RETURN_NONE;
24622473
}
2463-
return dictiter_new(ds->ds_dict, &PyDictIterItem_Type);
2474+
return dictiter_new(dv->dv_dict, &PyDictIterItem_Type);
2475+
}
2476+
2477+
static int
2478+
dictitems_contains(dictviewobject *dv, PyObject *obj)
2479+
{
2480+
PyObject *key, *value, *found;
2481+
if (dv->dv_dict == NULL)
2482+
return 0;
2483+
if (!PyTuple_Check(obj) || PyTuple_GET_SIZE(obj) != 2)
2484+
return 0;
2485+
key = PyTuple_GET_ITEM(obj, 0);
2486+
value = PyTuple_GET_ITEM(obj, 1);
2487+
found = PyDict_GetItem((PyObject *)dv->dv_dict, key);
2488+
if (found == NULL) {
2489+
if (PyErr_Occurred())
2490+
return -1;
2491+
return 0;
2492+
}
2493+
return PyObject_RichCompareBool(value, found, Py_EQ);
24642494
}
24652495

24662496
static PySequenceMethods dictitems_as_sequence = {
@@ -2471,7 +2501,7 @@ static PySequenceMethods dictitems_as_sequence = {
24712501
0, /* sq_slice */
24722502
0, /* sq_ass_item */
24732503
0, /* sq_ass_slice */
2474-
(objobjproc)0, /* sq_contains */
2504+
(objobjproc)dictitems_contains, /* sq_contains */
24752505
};
24762506

24772507
static PyMethodDef dictitems_methods[] = {
@@ -2518,15 +2548,15 @@ dictitems_new(PyObject *dict)
25182548
return dictview_new(dict, &PyDictItems_Type);
25192549
}
25202550

2521-
/* dict_values */
2551+
/*** dict_values ***/
25222552

25232553
static PyObject *
2524-
dictvalues_iter(dictviewobject *ds)
2554+
dictvalues_iter(dictviewobject *dv)
25252555
{
2526-
if (ds->ds_dict == NULL) {
2556+
if (dv->dv_dict == NULL) {
25272557
Py_RETURN_NONE;
25282558
}
2529-
return dictiter_new(ds->ds_dict, &PyDictIterValue_Type);
2559+
return dictiter_new(dv->dv_dict, &PyDictIterValue_Type);
25302560
}
25312561

25322562
static PySequenceMethods dictvalues_as_sequence = {

0 commit comments

Comments
 (0)