summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRaymond Hettinger <python@rcn.com>2002-11-27 07:29:33 (GMT)
committerRaymond Hettinger <python@rcn.com>2002-11-27 07:29:33 (GMT)
commite33d3df03079d704edbe159be079dc387058f044 (patch)
treeb9b68ea6479278b215f1ed03ee75ac9e4fcc03ce
parente9cfcef71eec755ad38a0764336920ecebb76344 (diff)
downloadcpython-e33d3df03079d704edbe159be079dc387058f044.zip
cpython-e33d3df03079d704edbe159be079dc387058f044.tar.gz
cpython-e33d3df03079d704edbe159be079dc387058f044.tar.bz2
SF Patch 643443. Added dict.fromkeys(iterable, value=None), a class
method for constructing new dictionaries from sequences of keys.
-rw-r--r--Doc/lib/libstdtypes.tex9
-rw-r--r--Lib/test/test_types.py28
-rw-r--r--Misc/NEWS5
-rw-r--r--Objects/dictobject.c56
4 files changed, 97 insertions, 1 deletions
diff --git a/Doc/lib/libstdtypes.tex b/Doc/lib/libstdtypes.tex
index eb12aa7..6f9e453 100644
--- a/Doc/lib/libstdtypes.tex
+++ b/Doc/lib/libstdtypes.tex
@@ -1055,8 +1055,11 @@ arbitrary objects):
{(3)}
\lineiii{\var{a}.keys()}{a copy of \var{a}'s list of keys}{(3)}
\lineiii{\var{a}.update(\var{b})}
- {\code{for k in \var{b}.keys(): \var{a}[k] = \var{b}[k]}}
+ {\code{for \var{k} in \var{b}.keys(): \var{a}[\var{k}] = \var{b}[\var{k}]}}
{}
+ \lineiii{\var{a}.fromkeys(\var{seq}\optional{, \var{value}})}
+ {Creates a new dictionary with keys from \var{seq} and values set to \var{value}}
+ {(7)}
\lineiii{\var{a}.values()}{a copy of \var{a}'s list of values}{(3)}
\lineiii{\var{a}.get(\var{k}\optional{, \var{x}})}
{\code{\var{a}[\var{k}]} if \code{\var{k} in \var{a}},
@@ -1116,6 +1119,10 @@ the dictionary as the value of \var{k}.
over a dictionary, as often used in set algorithms.
\end{description}
+\item[(7)] \function{fromkeys()} is a class method that returns a
+new dictionary. \var{value} defaults to \code{None}. \versionadded{2.3}
+\end{description}
+
\subsection{File Objects
\label{bltin-file-objects}}
diff --git a/Lib/test/test_types.py b/Lib/test/test_types.py
index c20af2e..9cfc680 100644
--- a/Lib/test/test_types.py
+++ b/Lib/test/test_types.py
@@ -530,6 +530,34 @@ class FailingUserDict:
try: d.update(FailingUserDict())
except ValueError: pass
else: raise TestFailed, 'dict.update(), __getitem__ expected ValueError'
+# dict.fromkeys()
+if dict.fromkeys('abc') != {'a':None, 'b':None, 'c':None}:
+ raise TestFailed, 'dict.fromkeys did not work as a class method'
+d = {}
+if d.fromkeys('abc') is d:
+ raise TestFailed, 'dict.fromkeys did not return a new dict'
+if d.fromkeys('abc') != {'a':None, 'b':None, 'c':None}:
+ raise TestFailed, 'dict.fromkeys failed with default value'
+if d.fromkeys((4,5),0) != {4:0, 5:0}:
+ raise TestFailed, 'dict.fromkeys failed with specified value'
+if d.fromkeys([]) != {}:
+ raise TestFailed, 'dict.fromkeys failed with null sequence'
+def g():
+ yield 1
+if d.fromkeys(g()) != {1:None}:
+ raise TestFailed, 'dict.fromkeys failed with a generator'
+try: {}.fromkeys(3)
+except TypeError: pass
+else: raise TestFailed, 'dict.fromkeys failed to raise TypeError'
+class dictlike(dict): pass
+if dictlike.fromkeys('a') != {'a':None}:
+ raise TestFailed, 'dictsubclass.fromkeys did not inherit'
+if dictlike().fromkeys('a') != {'a':None}:
+ raise TestFailed, 'dictsubclass.fromkeys did not inherit'
+if type(dictlike.fromkeys('a')) is not dictlike:
+ raise TestFailed, 'dictsubclass.fromkeys created wrong type'
+if type(dictlike().fromkeys('a')) is not dictlike:
+ raise TestFailed, 'dictsubclass.fromkeys created wrong type'
# dict.copy()
d = {1:1, 2:2, 3:3}
if d.copy() != {1:1, 2:2, 3:3}: raise TestFailed, 'dict copy'
diff --git a/Misc/NEWS b/Misc/NEWS
index 89303ba..066f8a5 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -270,6 +270,11 @@ Core and builtins
an optional argument that specifies the characters to strip. For
example, "Foo!!!?!?!?".rstrip("?!") -> "Foo".
+- Dictionaries have a new class method, fromkeys(iterable, value=None).
+ It constructs a new dictionary with keys taken from the iterable and
+ all values set to a single value. It is used for building membership
+ tests and for removing duplicates from sequences.
+
- Added a new dict method pop(key). This removes and returns the
value corresponding to key. [SF patch #539949]
diff --git a/Objects/dictobject.c b/Objects/dictobject.c
index 2eaa20c..b8ba7e1 100644
--- a/Objects/dictobject.c
+++ b/Objects/dictobject.c
@@ -963,6 +963,56 @@ dict_items(register dictobject *mp)
}
static PyObject *
+dict_fromkeys(PyObject *mp, PyObject *args)
+{
+ PyObject *seq;
+ PyObject *value = Py_None;
+ PyObject *it; /* iter(seq) */
+ PyObject *key;
+ PyObject *d;
+ PyObject *cls;
+ int status;
+
+ if (!PyArg_ParseTuple(args, "OO|O:fromkeys", &cls, &seq, &value))
+ return NULL;
+
+ d = PyObject_CallObject(cls, NULL);
+ if (d == NULL)
+ return NULL;
+ if (!PyDict_Check(d)) {
+ PyErr_BadInternalCall();
+ return NULL;
+ }
+
+ it = PyObject_GetIter(seq);
+ if (it == NULL){
+ Py_DECREF(d);
+ return NULL;
+ }
+
+ for (;;) {
+ key = PyIter_Next(it);
+ if (key == NULL) {
+ if (PyErr_Occurred())
+ goto Fail;
+ break;
+ }
+ status = PyDict_SetItem(d, key, value);
+ Py_DECREF(key);
+ if (status < 0)
+ goto Fail;
+ }
+
+ Py_DECREF(it);
+ return d;
+
+Fail:
+ Py_DECREF(it);
+ Py_DECREF(d);
+ return NULL;
+}
+
+static PyObject *
dict_update(PyObject *mp, PyObject *other)
{
if (PyDict_Update(mp, other) < 0)
@@ -1682,6 +1732,10 @@ PyDoc_STRVAR(values__doc__,
PyDoc_STRVAR(update__doc__,
"D.update(E) -> None. Update D from E: for k in E.keys(): D[k] = E[k]");
+PyDoc_STRVAR(fromkeys__doc__,
+"dict.fromkeys(S[,v]) -> New dict with keys from S and values equal to v.\n\
+v defaults to None.");
+
PyDoc_STRVAR(clear__doc__,
"D.clear() -> None. Remove all items from D.");
@@ -1716,6 +1770,8 @@ static PyMethodDef mapp_methods[] = {
values__doc__},
{"update", (PyCFunction)dict_update, METH_O,
update__doc__},
+ {"fromkeys", (PyCFunction)dict_fromkeys, METH_VARARGS | METH_CLASS,
+ fromkeys__doc__},
{"clear", (PyCFunction)dict_clear, METH_NOARGS,
clear__doc__},
{"copy", (PyCFunction)dict_copy, METH_NOARGS,