diff --git a/Doc/lib/libstdtypes.tex b/Doc/lib/libstdtypes.tex index 91dd67599d6e38..b66de07b55deef 100644 --- a/Doc/lib/libstdtypes.tex +++ b/Doc/lib/libstdtypes.tex @@ -783,8 +783,12 @@ \subsection{Mapping Types \label{typesmapping}} \ttindex{has_key()} \ttindex{items()} \ttindex{keys()} + \ttindex{firstitem()} + \ttindex{firstkey()} \ttindex{update()} \ttindex{values()} + \ttindex{firstvalue()} + \ttindex{setdefault()} \ttindex{get()}} \begin{tableiii}{c|l|c}{code}{Operation}{Result}{Notes} @@ -804,11 +808,19 @@ \subsection{Mapping Types \label{typesmapping}} \lineiii{\var{a}.items()} {a copy of \var{a}'s list of (\var{key}, \var{value}) pairs} {(2)} + \lineiii{\var{a}.firstitem()} + {a (\var{key}, \var{value}) pair, the first one in \var{a}.items()} + {(2)} \lineiii{\var{a}.keys()}{a copy of \var{a}'s list of keys}{(2)} + \lineiii{\var{a}.firstkey()} + {the first element in \var{a}.keys()} + {(2)} \lineiii{\var{a}.update(\var{b})} {\code{for k in \var{b}.keys(): \var{a}[k] = \var{b}[k]}} {(3)} \lineiii{\var{a}.values()}{a copy of \var{a}'s list of values}{(2)} + \lineiii{\var{a}.firstvalue()} + {the first element in \var{a}.values()} \lineiii{\var{a}.get(\var{k}\optional{, \var{x}})} {\code{\var{a}[\var{k}]} if \code{\var{a}.has_key(\var{k})}, else \var{x}} diff --git a/Lib/test/test_types.py b/Lib/test/test_types.py index eec9e2d7a358f5..06b001ad27e1d5 100644 --- a/Lib/test/test_types.py +++ b/Lib/test/test_types.py @@ -265,3 +265,9 @@ def myComparison(x,y): d.setdefault('key', []).append(4) if len(d['key']) <> 2: raise TestFailed, 'present {} setdefault, w/ 2nd arg' +if d.keys()[0] != d.firstkey(): + raise TestFailed, 'first key is not first in keys' +if d.values()[0] != d.firstvalue(): + raise TestFailed, 'first value is not first in values' +if d.items()[0] != d.firstitem(): + raise TestFailed, 'first item is not first in items' diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 7be1c67de079a8..ecc94cd4647274 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -708,6 +708,75 @@ static PyMappingMethods dict_as_mapping = { (objobjargproc)dict_ass_sub, /*mp_ass_subscript*/ }; +static PyObject * +dict_firstkey(register dictobject *mp, PyObject *args) +{ + register int i; + + if (!PyArg_NoArgs(args)) + return NULL; + if (mp->ma_used == 0) { + PyErr_SetString(PyExc_ValueError, "empty dictionary"); + return NULL; + } + for (i = 0; i < mp->ma_size; i++) { + if (mp->ma_table[i].me_value != NULL) { + PyObject *key = mp->ma_table[i].me_key; + Py_INCREF(key); + return key; + } + } +} + +static PyObject * +dict_firstvalue(register dictobject *mp, PyObject *args) +{ + register int i; + + if (!PyArg_NoArgs(args)) + return NULL; + if (mp->ma_used == 0) { + PyErr_SetString(PyExc_ValueError, "empty dictionary"); + return NULL; + } + for (i = 0; i < mp->ma_size; i++) { + if (mp->ma_table[i].me_value != NULL) { + PyObject *value = mp->ma_table[i].me_value; + Py_INCREF(value); + return value; + } + } +} + +static PyObject * +dict_firstitem(register dictobject *mp, PyObject *args) +{ + register int i; + + if (!PyArg_NoArgs(args)) + return NULL; + if (mp->ma_used == 0) { + PyErr_SetString(PyExc_ValueError, "empty dictionary"); + return NULL; + } + for (i = 0; i < mp->ma_size; i++) { + if (mp->ma_table[i].me_value != NULL) { + PyObject *key = mp->ma_table[i].me_key; + PyObject *value = mp->ma_table[i].me_value; + PyObject *item = PyTuple_New(2); + if (item == NULL) { + return NULL; + } + Py_INCREF(key); + PyTuple_SetItem(item, 0, key); + Py_INCREF(value); + PyTuple_SetItem(item, 1, value); + return item; + } + } +} + + static PyObject * dict_keys(register dictobject *mp, PyObject *args) { @@ -1162,6 +1231,9 @@ static PyMethodDef mapp_methods[] = { {"keys", (PyCFunction)dict_keys}, {"items", (PyCFunction)dict_items}, {"values", (PyCFunction)dict_values}, + {"firstkey", (PyCFunction)dict_firstkey}, + {"firstitem", (PyCFunction)dict_firstitem}, + {"firstvalue", (PyCFunction)dict_firstvalue}, {"update", (PyCFunction)dict_update}, {"clear", (PyCFunction)dict_clear}, {"copy", (PyCFunction)dict_copy},