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

Skip to content

Commit b90c848

Browse files
committed
Very preliminary work on dict views.
1 parent 8b54536 commit b90c848

2 files changed

Lines changed: 268 additions & 4 deletions

File tree

Lib/test/test_dictviews.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import unittest
2+
from test import test_support
3+
4+
class DictSetTest(unittest.TestCase):
5+
6+
def test_dict_keys(self):
7+
d = {1: 10, "a": "ABC"}
8+
keys = d.KEYS()
9+
self.assertEqual(set(keys), {1, "a"})
10+
11+
def test_dict_items(self):
12+
d = {1: 10, "a": "ABC"}
13+
items = d.ITEMS()
14+
self.assertEqual(set(items), {(1, 10), ("a", "ABC")})
15+
16+
def test_dict_values(self):
17+
d = {1: 10, "a": "ABC"}
18+
values = d.VALUES()
19+
self.assertEqual(set(values), {10, "ABC"})
20+
21+
def test_main():
22+
test_support.run_unittest(DictSetTest)
23+
24+
if __name__ == "__main__":
25+
test_main()

Objects/dictobject.c

Lines changed: 243 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1808,8 +1808,8 @@ PyDoc_STRVAR(values__doc__,
18081808
"D.values() -> list of D's values");
18091809

18101810
PyDoc_STRVAR(update__doc__,
1811-
"D.update(E, **F) -> None. Update D from E and F: for k in E: D[k] = E[k]\n\
1812-
(if E has keys else: for (k, v) in E: D[k] = v) then: for k in F: D[k] = F[k]");
1811+
"D.update(E, **F) -> None. Update D from E and F: for k in E: D[k] = E[k]\
1812+
\n(if E has keys else: for (k, v) in E: D[k] = v) then: for k in F: D[k] = F[k]");
18131813

18141814
PyDoc_STRVAR(fromkeys__doc__,
18151815
"dict.fromkeys(S[,v]) -> New dict with keys from S and values equal to v.\n\
@@ -1830,6 +1830,15 @@ PyDoc_STRVAR(itervalues__doc__,
18301830
PyDoc_STRVAR(iteritems__doc__,
18311831
"D.iteritems() -> an iterator over the (key, value) items of D");
18321832

1833+
/* Forward */
1834+
static PyObject *dictkeys_new(PyObject *);
1835+
static PyObject *dictitems_new(PyObject *);
1836+
static PyObject *dictvalues_new(PyObject *);
1837+
1838+
PyDoc_STRVAR(KEYS__doc__, "D.KEYS() -> a set-like object for D's keys");
1839+
PyDoc_STRVAR(ITEMS__doc__, "D.ITEMS() -> a set-like object for D's items");
1840+
PyDoc_STRVAR(VALUES__doc__, "D.VALUES() -> a set-like object for D's values");
1841+
18331842
static PyMethodDef mapp_methods[] = {
18341843
{"__contains__",(PyCFunction)dict_contains, METH_O | METH_COEXIST,
18351844
contains__doc__},
@@ -1845,6 +1854,12 @@ static PyMethodDef mapp_methods[] = {
18451854
popitem__doc__},
18461855
{"keys", (PyCFunction)dict_keys, METH_NOARGS,
18471856
keys__doc__},
1857+
{"KEYS", (PyCFunction)dictkeys_new, METH_NOARGS,
1858+
KEYS__doc__},
1859+
{"ITEMS", (PyCFunction)dictitems_new, METH_NOARGS,
1860+
ITEMS__doc__},
1861+
{"VALUES", (PyCFunction)dictvalues_new, METH_NOARGS,
1862+
VALUES__doc__},
18481863
{"items", (PyCFunction)dict_items, METH_NOARGS,
18491864
items__doc__},
18501865
{"values", (PyCFunction)dict_values, METH_NOARGS,
@@ -2078,10 +2093,12 @@ dictiter_len(dictiterobject *di)
20782093
return PyInt_FromSize_t(len);
20792094
}
20802095

2081-
PyDoc_STRVAR(length_hint_doc, "Private method returning an estimate of len(list(it)).");
2096+
PyDoc_STRVAR(length_hint_doc,
2097+
"Private method returning an estimate of len(list(it)).");
20822098

20832099
static PyMethodDef dictiter_methods[] = {
2084-
{"__length_hint__", (PyCFunction)dictiter_len, METH_NOARGS, length_hint_doc},
2100+
{"__length_hint__", (PyCFunction)dictiter_len, METH_NOARGS,
2101+
length_hint_doc},
20852102
{NULL, NULL} /* sentinel */
20862103
};
20872104

@@ -2317,3 +2334,225 @@ PyTypeObject PyDictIterItem_Type = {
23172334
dictiter_methods, /* tp_methods */
23182335
0,
23192336
};
2337+
2338+
2339+
/* View objects for keys(), items(), values(). */
2340+
/* While this is incomplete, we use KEYS(), ITEMS(), VALUES(). */
2341+
2342+
/* The instance lay-out is the same for all three; but the type differs. */
2343+
2344+
typedef struct {
2345+
PyObject_HEAD
2346+
dictobject *ds_dict;
2347+
} dictviewobject;
2348+
2349+
2350+
static void
2351+
dictview_dealloc(dictviewobject *ds)
2352+
{
2353+
Py_XDECREF(ds->ds_dict);
2354+
PyObject_Del(ds);
2355+
}
2356+
2357+
static PyObject *
2358+
dictview_length_hint(dictviewobject *ds)
2359+
{
2360+
Py_ssize_t len = 0;
2361+
if (ds->ds_dict != NULL)
2362+
len = ds->ds_dict->ma_used;
2363+
return PyInt_FromSize_t(len);
2364+
}
2365+
2366+
static PyObject *
2367+
dictview_new(PyObject *dict, PyTypeObject *type)
2368+
{
2369+
dictviewobject *ds;
2370+
if (dict == NULL) {
2371+
PyErr_BadInternalCall();
2372+
return NULL;
2373+
}
2374+
if (!PyDict_Check(dict)) {
2375+
/* XXX Get rid of this restriction later */
2376+
PyErr_Format(PyExc_TypeError,
2377+
"%s() requires a dict argument, not '%s'",
2378+
type->tp_name, dict->ob_type->tp_name);
2379+
return NULL;
2380+
}
2381+
ds = PyObject_New(dictviewobject, type);
2382+
if (ds == NULL)
2383+
return NULL;
2384+
Py_INCREF(dict);
2385+
ds->ds_dict = (dictobject *)dict;
2386+
return (PyObject *)ds;
2387+
}
2388+
2389+
/* dict_keys */
2390+
2391+
static PyObject *
2392+
dictkeys_iter(dictviewobject *ds)
2393+
{
2394+
if (ds->ds_dict == NULL) {
2395+
Py_RETURN_NONE;
2396+
}
2397+
return dictiter_new(ds->ds_dict, &PyDictIterKey_Type);
2398+
}
2399+
2400+
static PyMethodDef dictkeys_methods[] = {
2401+
{"__length_hint__", (PyCFunction)dictview_length_hint, METH_NOARGS,
2402+
length_hint_doc},
2403+
{NULL, NULL} /* sentinel */
2404+
};
2405+
2406+
PyTypeObject PyDictKeys_Type = {
2407+
PyObject_HEAD_INIT(&PyType_Type)
2408+
0, /* ob_size */
2409+
"dict_keys", /* tp_name */
2410+
sizeof(dictviewobject), /* tp_basicsize */
2411+
0, /* tp_itemsize */
2412+
/* methods */
2413+
(destructor)dictview_dealloc, /* tp_dealloc */
2414+
0, /* tp_print */
2415+
0, /* tp_getattr */
2416+
0, /* tp_setattr */
2417+
0, /* tp_compare */
2418+
0, /* tp_repr */
2419+
0, /* tp_as_number */
2420+
0, /* tp_as_sequence */
2421+
0, /* tp_as_mapping */
2422+
0, /* tp_hash */
2423+
0, /* tp_call */
2424+
0, /* tp_str */
2425+
PyObject_GenericGetAttr, /* tp_getattro */
2426+
0, /* tp_setattro */
2427+
0, /* tp_as_buffer */
2428+
Py_TPFLAGS_DEFAULT, /* tp_flags */
2429+
0, /* tp_doc */
2430+
0, /* tp_traverse */
2431+
0, /* tp_clear */
2432+
0, /* tp_richcompare */
2433+
0, /* tp_weaklistoffset */
2434+
(getiterfunc)dictkeys_iter, /* tp_iter */
2435+
0, /* tp_iternext */
2436+
dictkeys_methods, /* tp_methods */
2437+
0,
2438+
};
2439+
2440+
static PyObject *
2441+
dictkeys_new(PyObject *dict)
2442+
{
2443+
return dictview_new(dict, &PyDictKeys_Type);
2444+
}
2445+
2446+
/* dict_items */
2447+
2448+
static PyObject *
2449+
dictitems_iter(dictviewobject *ds)
2450+
{
2451+
if (ds->ds_dict == NULL) {
2452+
Py_RETURN_NONE;
2453+
}
2454+
return dictiter_new(ds->ds_dict, &PyDictIterItem_Type);
2455+
}
2456+
2457+
static PyMethodDef dictitems_methods[] = {
2458+
{"__length_hint__", (PyCFunction)dictview_length_hint, METH_NOARGS,
2459+
length_hint_doc},
2460+
{NULL, NULL} /* sentinel */
2461+
};
2462+
2463+
PyTypeObject PyDictItems_Type = {
2464+
PyObject_HEAD_INIT(&PyType_Type)
2465+
0, /* ob_size */
2466+
"dict_items", /* tp_name */
2467+
sizeof(dictviewobject), /* tp_basicsize */
2468+
0, /* tp_itemsize */
2469+
/* methods */
2470+
(destructor)dictview_dealloc, /* tp_dealloc */
2471+
0, /* tp_print */
2472+
0, /* tp_getattr */
2473+
0, /* tp_setattr */
2474+
0, /* tp_compare */
2475+
0, /* tp_repr */
2476+
0, /* tp_as_number */
2477+
0, /* tp_as_sequence */
2478+
0, /* tp_as_mapping */
2479+
0, /* tp_hash */
2480+
0, /* tp_call */
2481+
0, /* tp_str */
2482+
PyObject_GenericGetAttr, /* tp_getattro */
2483+
0, /* tp_setattro */
2484+
0, /* tp_as_buffer */
2485+
Py_TPFLAGS_DEFAULT, /* tp_flags */
2486+
0, /* tp_doc */
2487+
0, /* tp_traverse */
2488+
0, /* tp_clear */
2489+
0, /* tp_richcompare */
2490+
0, /* tp_weaklistoffset */
2491+
(getiterfunc)dictitems_iter, /* tp_iter */
2492+
0, /* tp_iternext */
2493+
dictitems_methods, /* tp_methods */
2494+
0,
2495+
};
2496+
2497+
static PyObject *
2498+
dictitems_new(PyObject *dict)
2499+
{
2500+
return dictview_new(dict, &PyDictItems_Type);
2501+
}
2502+
2503+
/* dict_values */
2504+
2505+
static PyObject *
2506+
dictvalues_iter(dictviewobject *ds)
2507+
{
2508+
if (ds->ds_dict == NULL) {
2509+
Py_RETURN_NONE;
2510+
}
2511+
return dictiter_new(ds->ds_dict, &PyDictIterValue_Type);
2512+
}
2513+
2514+
static PyMethodDef dictvalues_methods[] = {
2515+
{"__length_hint__", (PyCFunction)dictview_length_hint, METH_NOARGS,
2516+
length_hint_doc},
2517+
{NULL, NULL} /* sentinel */
2518+
};
2519+
2520+
PyTypeObject PyDictValues_Type = {
2521+
PyObject_HEAD_INIT(&PyType_Type)
2522+
0, /* ob_size */
2523+
"dict_values", /* tp_name */
2524+
sizeof(dictviewobject), /* tp_basicsize */
2525+
0, /* tp_itemsize */
2526+
/* methods */
2527+
(destructor)dictview_dealloc, /* tp_dealloc */
2528+
0, /* tp_print */
2529+
0, /* tp_getattr */
2530+
0, /* tp_setattr */
2531+
0, /* tp_compare */
2532+
0, /* tp_repr */
2533+
0, /* tp_as_number */
2534+
0, /* tp_as_sequence */
2535+
0, /* tp_as_mapping */
2536+
0, /* tp_hash */
2537+
0, /* tp_call */
2538+
0, /* tp_str */
2539+
PyObject_GenericGetAttr, /* tp_getattro */
2540+
0, /* tp_setattro */
2541+
0, /* tp_as_buffer */
2542+
Py_TPFLAGS_DEFAULT, /* tp_flags */
2543+
0, /* tp_doc */
2544+
0, /* tp_traverse */
2545+
0, /* tp_clear */
2546+
0, /* tp_richcompare */
2547+
0, /* tp_weaklistoffset */
2548+
(getiterfunc)dictvalues_iter, /* tp_iter */
2549+
0, /* tp_iternext */
2550+
dictvalues_methods, /* tp_methods */
2551+
0,
2552+
};
2553+
2554+
static PyObject *
2555+
dictvalues_new(PyObject *dict)
2556+
{
2557+
return dictview_new(dict, &PyDictValues_Type);
2558+
}

0 commit comments

Comments
 (0)