]> granicus.if.org Git - python/commitdiff
SF #904720: dict.update should take a 2-tuple sequence like dict.__init_
authorRaymond Hettinger <python@rcn.com>
Thu, 4 Mar 2004 08:25:44 +0000 (08:25 +0000)
committerRaymond Hettinger <python@rcn.com>
Thu, 4 Mar 2004 08:25:44 +0000 (08:25 +0000)
(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.

Doc/lib/libstdtypes.tex
Doc/whatsnew/whatsnew24.tex
Lib/UserDict.py
Lib/os.py
Lib/test/test_call.py
Lib/test/test_types.py
Lib/test/test_userdict.py
Lib/weakref.py
Misc/ACKS
Misc/NEWS
Objects/dictobject.c

index 7c5cba0dc9e8cc67f073d7bfc5f1f382c2275ad9..c39be284b17ec05c4b2efbe9efa42586f404a334 100644 (file)
@@ -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}}
index eb377bec68d005a4f22a2fb21e481a155c78089e..24650fa5bc8b6fa240c6be1ae73792fb1b99aa70 100644 (file)
@@ -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.
index 8141e7f31be8b9a2086522d2bbd47df663bb6169..87cc6a35a96c74f7ce17df024aebd9acdf5c0fde 100644 (file)
@@ -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]
index 8cec9125ad77d918c98aca0d399a3ac541db222b..fdb9a4604adf0cdcf5a9d3f2726ac3294644ceb8 100644 (file)
--- 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:
index 99554c7b9cf34d93ebe96db931b0ef7327b35304..f3c7c8c394f90573b3fea9fb4b3b43bb3d587600 100644 (file)
@@ -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():
index aa8f854db02c4377aa53f425d9bd6a193925543d..4b4e19cd76864353bcc818834b623d84e7c1a40a 100644 (file)
@@ -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):
index 602fd90551b92bc26094b019803db4b71a5335a1..0ed436998c801c132a508cd2dcf47270f0442bf3 100644 (file)
@@ -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)
index 09bed6560e6034ba23d5adc5df73d1b5f2e6a6ea..5c661861b034c0e4b26c74f1987d52dc786608e5 100644 (file)
@@ -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:
index 61b07cba53ee713902c6e65c87d63afb0b1e2ba4..befc46bfab08712669298b19d84f702a210153ba 100644 (file)
--- 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
index 1bd6c2b7f876177ce88f07cb6162c1758659b3c4..72232c8de85bc792dab8702c42d80f44ab724325 100644 (file)
--- 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.
index eb0222cdd56d9e970e10f7852183b23ce2e06c88..b5cbd667d94492390ac87f93ff3b6edd097d360c 100644 (file)
@@ -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