diff --git a/Doc/lib/libstdtypes.tex b/Doc/lib/libstdtypes.tex index f42f84e985f..a619105cbaa 100644 --- a/Doc/lib/libstdtypes.tex +++ b/Doc/lib/libstdtypes.tex @@ -992,6 +992,9 @@ arbitrary objects): {\code{\var{a}[\var{k}]} if \code{\var{k} in \var{a}}, else \var{x} (also setting it)} {(5)} + \lineiii{\var{a}.pop(\var{k})} + {remove specified \var{key} and return corresponding \var{value}} + {} \lineiii{\var{a}.popitem()} {remove and return an arbitrary (\var{key}, \var{value}) pair} {(6)} diff --git a/Lib/test/test_types.py b/Lib/test/test_types.py index 26535c49050..9d4508b16a6 100644 --- a/Lib/test/test_types.py +++ b/Lib/test/test_types.py @@ -476,6 +476,21 @@ try: d.popitem() except KeyError: pass else: raise TestFailed, "{}.popitem doesn't raise KeyError" +# Tests for pop with specified key +d.clear() +k, v = 'abc', 'def' +d[k] = v +try: d.pop('ghi') +except KeyError: pass +else: raise TestFailed, "{}.pop(k) doesn't raise KeyError when k not in dictionary" + +if d.pop(k) != v: raise TestFailed, "{}.pop(k) doesn't find known key/value pair" +if len(d) > 0: raise TestFailed, "{}.pop(k) failed to remove the specified pair" + +try: d.pop(k) +except KeyError: pass +else: raise TestFailed, "{}.pop(k) doesn't raise KeyError when dictionary is empty" + d[1] = 1 try: for i in d: diff --git a/Objects/dictobject.c b/Objects/dictobject.c index ffc057933eb..1bd2f64143a 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -1494,6 +1494,39 @@ dict_clear(register dictobject *mp) return Py_None; } +static PyObject * +dict_pop(dictobject *mp, PyObject *key) +{ + long hash; + dictentry *ep; + PyObject *old_value, *old_key; + + if (mp->ma_used == 0) { + PyErr_SetString(PyExc_KeyError, + "pop(): dictionary is empty"); + return NULL; + } + if (!PyString_CheckExact(key) || + (hash = ((PyStringObject *) key)->ob_shash) == -1) { + hash = PyObject_Hash(key); + if (hash == -1) + return NULL; + } + ep = (mp->ma_lookup)(mp, key, hash); + if (ep->me_value == NULL) { + PyErr_SetObject(PyExc_KeyError, key); + return NULL; + } + old_key = ep->me_key; + Py_INCREF(dummy); + ep->me_key = dummy; + old_value = ep->me_value; + ep->me_value = NULL; + mp->ma_used--; + Py_DECREF(old_key); + return old_value; +} + static PyObject * dict_popitem(dictobject *mp) { @@ -1636,6 +1669,9 @@ static char get__doc__[] = static char setdefault_doc__[] = "D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if not D.has_key(k)"; +static char pop__doc__[] = +"D.pop(k) -> v, remove specified key and return the corresponding value"; + static char popitem__doc__[] = "D.popitem() -> (k, v), remove and return some (key, value) pair as a\n\ 2-tuple; but raise KeyError if D is empty"; @@ -1674,6 +1710,8 @@ static PyMethodDef mapp_methods[] = { get__doc__}, {"setdefault", (PyCFunction)dict_setdefault, METH_VARARGS, setdefault_doc__}, + {"pop", (PyCFunction)dict_pop, METH_O, + pop__doc__}, {"popitem", (PyCFunction)dict_popitem, METH_NOARGS, popitem__doc__}, {"keys", (PyCFunction)dict_keys, METH_NOARGS,