summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRaymond Hettinger <python@rcn.com>2004-03-04 08:25:44 (GMT)
committerRaymond Hettinger <python@rcn.com>2004-03-04 08:25:44 (GMT)
commit31017aed36a5c5b0e4b16ca58bea09c9ce360134 (patch)
tree766d70bb4fbb6878a71c81fc3874515cfcbc8aa8
parent6c79a518e70ea8e45e3287573d99c648ae3cb21b (diff)
downloadcpython-31017aed36a5c5b0e4b16ca58bea09c9ce360134.zip
cpython-31017aed36a5c5b0e4b16ca58bea09c9ce360134.tar.gz
cpython-31017aed36a5c5b0e4b16ca58bea09c9ce360134.tar.bz2
SF #904720: dict.update should take a 2-tuple sequence like dict.__init_
(Championed by Bob Ippolito.) The update() method for mappings now accepts all the same argument forms as the dict() constructor. This includes item lists and/or keyword arguments.
-rw-r--r--Doc/lib/libstdtypes.tex13
-rw-r--r--Doc/whatsnew/whatsnew24.tex4
-rw-r--r--Lib/UserDict.py28
-rw-r--r--Lib/os.py6
-rw-r--r--Lib/test/test_call.py18
-rw-r--r--Lib/test/test_types.py2
-rw-r--r--Lib/test/test_userdict.py6
-rw-r--r--Lib/weakref.py22
-rw-r--r--Misc/ACKS1
-rw-r--r--Misc/NEWS4
-rw-r--r--Objects/dictobject.c42
11 files changed, 91 insertions, 55 deletions
diff --git a/Doc/lib/libstdtypes.tex b/Doc/lib/libstdtypes.tex
index 7c5cba0..c39be28 100644
--- a/Doc/lib/libstdtypes.tex
+++ b/Doc/lib/libstdtypes.tex
@@ -1266,9 +1266,9 @@ arbitrary objects):
{a copy of \var{a}'s list of (\var{key}, \var{value}) pairs}
{(3)}
\lineiii{\var{a}.keys()}{a copy of \var{a}'s list of keys}{(3)}
- \lineiii{\var{a}.update(\var{b})}
- {\code{for \var{k} in \var{b}.keys(): \var{a}[\var{k}] = \var{b}[\var{k}]}}
- {}
+ \lineiii{\var{a}.update(\optional{\var{b}})}
+ {updates (and overwrites) key/value pairs from \var{b}}
+ {(9)}
\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)}
@@ -1338,6 +1338,13 @@ new dictionary. \var{value} defaults to \code{None}. \versionadded{2.3}
value is given and the key is not found. \versionadded{2.3}
\end{description}
+\item[(9)] \function{update()} accepts either another mapping object
+or an iterable of key/value pairs (as a tuple or other iterable of
+length two). If keyword arguments are specified, the mapping is
+then is updated with those key/value pairs:
+\samp{d.update(red=1, blue=2)}.
+\versionchanged[Allowed the argument to be an iterable of key/value
+ pairs and allowed keyword arguments]{2.4}
\subsection{File Objects
\label{bltin-file-objects}}
diff --git a/Doc/whatsnew/whatsnew24.tex b/Doc/whatsnew/whatsnew24.tex
index eb377be..24650fa 100644
--- a/Doc/whatsnew/whatsnew24.tex
+++ b/Doc/whatsnew/whatsnew24.tex
@@ -134,6 +134,10 @@ language.
\begin{itemize}
+\item The \method{dict.update()} method now accepts the same
+argument forms as the \class{dict} constructor. This includes any
+mapping, any iterable of key/value pairs, and/or keyword arguments.
+
\item The string methods, \method{ljust()}, \method{rjust()}, and
\method{center()} now take an optional argument for specifying a
fill character other than a space.
diff --git a/Lib/UserDict.py b/Lib/UserDict.py
index 8141e7f..87cc6a3 100644
--- a/Lib/UserDict.py
+++ b/Lib/UserDict.py
@@ -4,8 +4,6 @@ class UserDict:
def __init__(self, dict=None, **kwargs):
self.data = {}
if dict is not None:
- if not hasattr(dict,'keys'):
- dict = type({})(dict) # make mapping from a sequence
self.update(dict)
if len(kwargs):
self.update(kwargs)
@@ -39,14 +37,18 @@ class UserDict:
def itervalues(self): return self.data.itervalues()
def values(self): return self.data.values()
def has_key(self, key): return self.data.has_key(key)
- def update(self, dict):
- if isinstance(dict, UserDict):
+ def update(self, dict=None, **kwargs):
+ if dict is None:
+ pass
+ elif isinstance(dict, UserDict):
self.data.update(dict.data)
- elif isinstance(dict, type(self.data)):
+ elif isinstance(dict, type({})) or not hasattr(dict, 'items'):
self.data.update(dict)
else:
for k, v in dict.items():
self[k] = v
+ if len(kwargs):
+ self.data.update(kwargs)
def get(self, key, failobj=None):
if not self.has_key(key):
return failobj
@@ -136,17 +138,21 @@ class DictMixin:
raise KeyError, 'container is empty'
del self[k]
return (k, v)
- def update(self, other):
+ def update(self, other=None, **kwargs):
# Make progressively weaker assumptions about "other"
- if hasattr(other, 'iteritems'): # iteritems saves memory and lookups
+ if other is None:
+ pass
+ elif hasattr(other, 'iteritems'): # iteritems saves memory and lookups
for k, v in other.iteritems():
self[k] = v
- elif hasattr(other, '__iter__'): # iter saves memory
- for k in other:
- self[k] = other[k]
- else:
+ elif hasattr(other, 'keys'):
for k in other.keys():
self[k] = other[k]
+ else:
+ for k, v in other:
+ self[k] = v
+ if kwargs:
+ self.update(kwargs)
def get(self, key, default=None):
try:
return self[key]
diff --git a/Lib/os.py b/Lib/os.py
index 8cec912..fdb9a46 100644
--- a/Lib/os.py
+++ b/Lib/os.py
@@ -433,9 +433,6 @@ else:
return key.upper() in self.data
def get(self, key, failobj=None):
return self.data.get(key.upper(), failobj)
- def update(self, dict):
- for k, v in dict.items():
- self[k] = v
def copy(self):
return dict(self)
@@ -447,9 +444,6 @@ else:
def __setitem__(self, key, item):
putenv(key, item)
self.data[key] = item
- def update(self, dict):
- for k, v in dict.items():
- self[k] = v
try:
unsetenv
except NameError:
diff --git a/Lib/test/test_call.py b/Lib/test/test_call.py
index 99554c7..f3c7c8c 100644
--- a/Lib/test/test_call.py
+++ b/Lib/test/test_call.py
@@ -86,41 +86,41 @@ class CFunctionCalls(unittest.TestCase):
self.assertRaises(TypeError, {}.keys, x=2, y=2)
def test_oldargs1_0(self):
- self.assertRaises(TypeError, {}.update)
+ self.assertRaises(TypeError, [].count)
def test_oldargs1_1(self):
- {}.update({})
+ [].count(1)
def test_oldargs1_2(self):
- self.assertRaises(TypeError, {}.update, {}, 1)
+ self.assertRaises(TypeError, [].count, 1, 2)
def test_oldargs1_0_ext(self):
try:
- {}.update(*())
+ [].count(*())
except TypeError:
pass
else:
raise RuntimeError
def test_oldargs1_1_ext(self):
- {}.update(*({},))
+ [].count(*(1,))
def test_oldargs1_2_ext(self):
try:
- {}.update(*({}, 2))
+ [].count(*(1, 2))
except TypeError:
pass
else:
raise RuntimeError
def test_oldargs1_0_kw(self):
- self.assertRaises(TypeError, {}.update, x=2)
+ self.assertRaises(TypeError, [].count, x=2)
def test_oldargs1_1_kw(self):
- self.assertRaises(TypeError, {}.update, {}, x=2)
+ self.assertRaises(TypeError, [].count, {}, x=2)
def test_oldargs1_2_kw(self):
- self.assertRaises(TypeError, {}.update, x=2, y=2)
+ self.assertRaises(TypeError, [].count, x=2, y=2)
def test_main():
diff --git a/Lib/test/test_types.py b/Lib/test/test_types.py
index aa8f854..4b4e19c 100644
--- a/Lib/test/test_types.py
+++ b/Lib/test/test_types.py
@@ -253,7 +253,7 @@ d.update({1:1, 2:2, 3:3})
if d != {1:1, 2:2, 3:3}: raise TestFailed, 'dict update'
d.clear()
try: d.update(None)
-except AttributeError: pass
+except (TypeError, AttributeError): pass
else: raise TestFailed, 'dict.update(None), AttributeError expected'
class SimpleUserDict:
def __init__(self):
diff --git a/Lib/test/test_userdict.py b/Lib/test/test_userdict.py
index 602fd90..0ed4369 100644
--- a/Lib/test/test_userdict.py
+++ b/Lib/test/test_userdict.py
@@ -93,8 +93,12 @@ class TestMappingProtocol(unittest.TestCase):
#update
p.update(self.reference)
self.assertEqual(dict(p), self.reference)
+ items = p.items()
+ p = self._empty_mapping()
+ p.update(items)
+ self.assertEqual(dict(p), self.reference)
d = self._full_mapping(self.reference)
- #setdefaullt
+ #setdefault
key, value = d.iteritems().next()
knownkey, knownvalue = self.other.iteritems().next()
self.assertEqual(d.setdefault(key, knownvalue), value)
diff --git a/Lib/weakref.py b/Lib/weakref.py
index 09bed65..5c66186 100644
--- a/Lib/weakref.py
+++ b/Lib/weakref.py
@@ -122,10 +122,15 @@ class WeakValueDictionary(UserDict.UserDict):
else:
return wr()
- def update(self, dict):
+ def update(self, dict=None, **kwargs):
d = self.data
- for key, o in dict.items():
- d[key] = ref(o, self.__makeremove(key))
+ if dict is not None:
+ if not hasattr(dict, "items"):
+ dict = type({})(dict)
+ for key, o in dict.items():
+ d[key] = ref(o, self.__makeremove(key))
+ if len(kwargs):
+ self.update(kwargs)
def values(self):
L = []
@@ -239,10 +244,15 @@ class WeakKeyDictionary(UserDict.UserDict):
def setdefault(self, key, default):
return self.data.setdefault(ref(key, self._remove),default)
- def update(self, dict):
+ def update(self, dict=None, **kwargs):
d = self.data
- for key, value in dict.items():
- d[ref(key, self._remove)] = value
+ if dict is not None:
+ if not hasattr(dict, "items"):
+ dict = type({})(dict)
+ for key, value in dict.items():
+ d[ref(key, self._remove)] = value
+ if len(kwargs):
+ self.update(kwargs)
class BaseIter:
diff --git a/Misc/ACKS b/Misc/ACKS
index 61b07cb..befc46b 100644
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -273,6 +273,7 @@ Mihai Ibanescu
Juan David Ibáñez Palomar
Tony Ingraldi
John Interrante
+Bob Ippolito
Ben Jackson
Paul Jackson
David Jacobs
diff --git a/Misc/NEWS b/Misc/NEWS
index 1bd6c2b..72232c8 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -32,6 +32,10 @@ Core and builtins
the overallocation is no more than three elements -- this improves space
utilization for applications that have large numbers of small lists.
+- The dict.update() method now accepts all the same argument forms
+ as the dict() constructor. This now includes item lists and/or
+ keyword arguments.
+
- Support for arbitrary objects supporting the read-only buffer
interface as the co_code field of code objects (something that was
only possible to create from C code) has been removed.
diff --git a/Objects/dictobject.c b/Objects/dictobject.c
index eb0222c..b5cbd66 100644
--- a/Objects/dictobject.c
+++ b/Objects/dictobject.c
@@ -1029,10 +1029,30 @@ Fail:
return NULL;
}
+static int
+dict_update_common(PyObject *self, PyObject *args, PyObject *kwds, char *methname)
+{
+ PyObject *arg = NULL;
+ int result = 0;
+
+ if (!PyArg_UnpackTuple(args, methname, 0, 1, &arg))
+ result = -1;
+
+ else if (arg != NULL) {
+ if (PyObject_HasAttrString(arg, "keys"))
+ result = PyDict_Merge(self, arg, 1);
+ else
+ result = PyDict_MergeFromSeq2(self, arg, 1);
+ }
+ if (result == 0 && kwds != NULL)
+ result = PyDict_Merge(self, kwds, 1);
+ return result;
+}
+
static PyObject *
-dict_update(PyObject *mp, PyObject *other)
+dict_update(PyObject *self, PyObject *args, PyObject *kwds)
{
- if (PyDict_Update(mp, other) < 0)
+ if (dict_update_common(self, args, kwds, "update") == -1)
return NULL;
Py_INCREF(Py_None);
return Py_None;
@@ -1806,7 +1826,7 @@ static PyMethodDef mapp_methods[] = {
items__doc__},
{"values", (PyCFunction)dict_values, METH_NOARGS,
values__doc__},
- {"update", (PyCFunction)dict_update, METH_O,
+ {"update", (PyCFunction)dict_update, METH_VARARGS | METH_KEYWORDS,
update__doc__},
{"fromkeys", (PyCFunction)dict_fromkeys, METH_VARARGS | METH_CLASS,
fromkeys__doc__},
@@ -1875,21 +1895,7 @@ dict_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
static int
dict_init(PyObject *self, PyObject *args, PyObject *kwds)
{
- PyObject *arg = NULL;
- int result = 0;
-
- if (!PyArg_UnpackTuple(args, "dict", 0, 1, &arg))
- result = -1;
-
- else if (arg != NULL) {
- if (PyObject_HasAttrString(arg, "keys"))
- result = PyDict_Merge(self, arg, 1);
- else
- result = PyDict_MergeFromSeq2(self, arg, 1);
- }
- if (result == 0 && kwds != NULL)
- result = PyDict_Merge(self, kwds, 1);
- return result;
+ return dict_update_common(self, args, kwds, "dict");
}
static long