Skip to content

Commit

Permalink
SF Patch 643443. Added dict.fromkeys(iterable, value=None), a class
Browse files Browse the repository at this point in the history
method for constructing new dictionaries from sequences of keys.
  • Loading branch information
rhettinger committed Nov 27, 2002
1 parent e9cfcef commit e33d3df
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 1 deletion.
9 changes: 8 additions & 1 deletion Doc/lib/libstdtypes.tex
Original file line number Diff line number Diff line change
Expand Up @@ -1055,8 +1055,11 @@ \subsection{Mapping Types \label{typesmapping}}
{(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}},
Expand Down Expand Up @@ -1116,6 +1119,10 @@ \subsection{Mapping Types \label{typesmapping}}
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}}
Expand Down
28 changes: 28 additions & 0 deletions Lib/test/test_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -530,6 +530,34 @@ def __getitem__(self, key):
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'
Expand Down
5 changes: 5 additions & 0 deletions Misc/NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -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]

Expand Down
56 changes: 56 additions & 0 deletions Objects/dictobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -962,6 +962,56 @@ dict_items(register dictobject *mp)
return v;
}

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)
{
Expand Down Expand Up @@ -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.");

Expand Down Expand Up @@ -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,
Expand Down

0 comments on commit e33d3df

Please sign in to comment.