From a797d8150dd6fd8336653d8e91db3c088f2c53ff Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Sat, 23 Nov 2002 09:45:04 +0000 Subject: Patch #642500 with slight modifications: allow keyword arguments in dict() constructor. Example: >>> dict(a=1, b=2) {'a': 1, 'b': 2} >>> --- Doc/lib/libfuncs.tex | 35 +++++++++++++++++++++-------------- Lib/test/test_descr.py | 23 ++++++++++++----------- Misc/NEWS | 6 ++++++ Objects/dictobject.c | 12 +++++++----- 4 files changed, 46 insertions(+), 30 deletions(-) diff --git a/Doc/lib/libfuncs.tex b/Doc/lib/libfuncs.tex index 9fab9ba..169cfc7 100644 --- a/Doc/lib/libfuncs.tex +++ b/Doc/lib/libfuncs.tex @@ -189,27 +189,34 @@ def my_import(name): \end{funcdesc} \begin{funcdesc}{dict}{\optional{mapping-or-sequence}} - Return a new dictionary initialized from the optional argument. - If an argument is not specified, return a new empty dictionary. - If the argument is a mapping object, return a dictionary mapping the - same keys to the same values as does the mapping object. - Else the argument must be a sequence, a container that supports - iteration, or an iterator object. The elements of the argument must - each also be of one of those kinds, and each must in turn contain + Return a new dictionary initialized from an optional positional + argument or from a set of keyword arguments. + If no arguments are given, return a new empty dictionary. + If the positional argument is a mapping object, return a dictionary + mapping the same keys to the same values as does the mapping object. + Otherwise the positional argument must be a sequence, a container that + supports iteration, or an iterator object. The elements of the argument + must each also be of one of those kinds, and each must in turn contain exactly two objects. The first is used as a key in the new dictionary, and the second as the key's value. If a given key is seen more than once, the last value associated with it is retained in the new dictionary. + + If keyword arguments are given, the keywords themselves with their + associated values are added as items to the dictionary. If a key + is specified both in the positional argument and as a keyword argument, + the value associated with the keyword is retained in the dictionary. For example, these all return a dictionary equal to - \code{\{1: 2, 2: 3\}}: + \code{\{"one": 2, "two": 3\}}: \begin{itemize} - \item \code{dict(\{1: 2, 2: 3\})} - \item \code{dict(\{1: 2, 2: 3\}.items())} - \item \code{dict(\{1: 2, 2: 3\}.iteritems())} - \item \code{dict(zip((1, 2), (2, 3)))} - \item \code{dict([[2, 3], [1, 2]])} - \item \code{dict([(i-1, i) for i in (2, 3)])} + \item \code{dict(\{'one': 2, 'two': 3\})} + \item \code{dict(\{'one': 2, 'two': 3\}.items())} + \item \code{dict(\{'one': 2, 'two': 3\}.iteritems())} + \item \code{dict(zip(('one', 'two'), (2, 3)))} + \item \code{dict([['two', 3], ['one', 2]])} + \item \code{dict(one=2, two=3)} + \item \code{dict([(['one', 'two'][i-2], i) for i in (2, 3)])} \end{itemize} \versionadded{2.2} diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py index 2e1f5af..95940ee 100644 --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -184,12 +184,19 @@ def dict_constructor(): vereq(d, {}) d = dict({}) vereq(d, {}) - d = dict(items={}) + d = dict({}) vereq(d, {}) d = dict({1: 2, 'a': 'b'}) vereq(d, {1: 2, 'a': 'b'}) vereq(d, dict(d.items())) - vereq(d, dict(items=d.iteritems())) + vereq(d, dict(d.iteritems())) + d = dict({'one':1, 'two':2}) + vereq(d, dict(one=1, two=2)) + vereq(d, dict(**d)) + vereq(d, dict({"one": 1}, two=2)) + vereq(d, dict([("two", 2)], one=1)) + vereq(d, dict([("one", 100), ("two", 200)], **d)) + verify(d is not dict(**d)) for badarg in 0, 0L, 0j, "0", [0], (0,): try: dict(badarg) @@ -205,12 +212,6 @@ def dict_constructor(): raise TestFailed("no TypeError from dict(%r)" % badarg) else: raise TestFailed("no TypeError from dict(%r)" % badarg) - try: - dict(senseless={}) - except TypeError: - pass - else: - raise TestFailed("no TypeError from dict(senseless={})") try: dict({}, {}) @@ -232,7 +233,7 @@ def dict_constructor(): Mapping.keys = lambda self: self.dict.keys() Mapping.__getitem__ = lambda self, i: self.dict[i] - d = dict(items=Mapping()) + d = dict(Mapping()) vereq(d, Mapping.dict) # Init from sequence of iterable objects, each producing a 2-sequence. @@ -2332,10 +2333,10 @@ def keywords(): vereq(unicode(string='abc', errors='strict'), u'abc') vereq(tuple(sequence=range(3)), (0, 1, 2)) vereq(list(sequence=(0, 1, 2)), range(3)) - vereq(dict(items={1: 2}), {1: 2}) + # note: as of Python 2.3, dict() no longer has an "items" keyword arg for constructor in (int, float, long, complex, str, unicode, - tuple, list, dict, file): + tuple, list, file): try: constructor(bogus_keyword_arg=1) except TypeError: diff --git a/Misc/NEWS b/Misc/NEWS index b248970..86cf16e 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -11,6 +11,12 @@ What's New in Python 2.3 alpha 1? Type/class unification and new-style classes -------------------------------------------- +- dict() now accepts keyword arguments so that dict(one=1,two=2) + is the equivalent of dict([('one',1),('two',2)]). Accordingly, + the existing (but undocumented) 'items' keyword argument has + been eliminated. This means that dict(items=someMapping) now has + a different meaning than before. + - int() now returns a long object if the argument is outside the integer range, so int("4"*1000), int(1e200) and int(1L<<1000) will all return long objects instead of raising an OverflowError. diff --git a/Objects/dictobject.c b/Objects/dictobject.c index e9726cf..2eaa20c 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -1705,7 +1705,7 @@ static PyMethodDef mapp_methods[] = { {"setdefault", (PyCFunction)dict_setdefault, METH_VARARGS, setdefault_doc__}, {"pop", (PyCFunction)dict_pop, METH_O, - pop__doc__}, + pop__doc__}, {"popitem", (PyCFunction)dict_popitem, METH_NOARGS, popitem__doc__}, {"keys", (PyCFunction)dict_keys, METH_NOARGS, @@ -1781,11 +1781,9 @@ static int dict_init(PyObject *self, PyObject *args, PyObject *kwds) { PyObject *arg = NULL; - static char *kwlist[] = {"items", 0}; int result = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O:dict", - kwlist, &arg)) + if (!PyArg_ParseTuple(args, "|O:dict", &arg)) result = -1; else if (arg != NULL) { @@ -1794,6 +1792,8 @@ dict_init(PyObject *self, PyObject *args, PyObject *kwds) else result = PyDict_MergeFromSeq2(self, arg, 1); } + if (result == 0 && kwds != NULL) + result = PyDict_Merge(self, kwds, 1); return result; } @@ -1817,7 +1817,9 @@ PyDoc_STRVAR(dictionary_doc, "dict(seq) -> new dictionary initialized as if via:\n" " d = {}\n" " for k, v in seq:\n" -" d[k] = v"); +" d[k] = v\n" +"dict(**kwargs) -> new dictionary initialized with the name=value pairs\n" +" in the keyword argument list. For example: dict(one=1, two=2)"); PyTypeObject PyDict_Type = { PyObject_HEAD_INIT(&PyType_Type) -- cgit v0.12