]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
Issue #29368: The extend() method is now called instead of the append()
authorSerhiy Storchaka <storchaka@gmail.com>
Thu, 2 Feb 2017 09:12:47 +0000 (11:12 +0200)
committerSerhiy Storchaka <storchaka@gmail.com>
Thu, 2 Feb 2017 09:12:47 +0000 (11:12 +0200)
method when unpickle collections.deque and other list-like objects.
This can speed up unpickling to 2 times.

Lib/pickle.py
Misc/NEWS
Modules/_pickle.c

index c8370c9f7e7ec60b1b608d7570ad6e3982ef025a..702b0b35cebdb70b63acb3165a6d1a34dcd1eece 100644 (file)
@@ -1464,12 +1464,19 @@ class _Unpickler:
     def load_appends(self):
         items = self.pop_mark()
         list_obj = self.stack[-1]
-        if isinstance(list_obj, list):
-            list_obj.extend(items)
+        try:
+            extend = list_obj.extend
+        except AttributeError:
+            pass
         else:
-            append = list_obj.append
-            for item in items:
-                append(item)
+            extend(items)
+            return
+        # Even if the PEP 307 requires extend() and append() methods,
+        # fall back on append() if the object has no extend() method
+        # for backward compatibility.
+        append = list_obj.append
+        for item in items:
+            append(item)
     dispatch[APPENDS[0]] = load_appends
 
     def load_setitem(self):
index 21685d3a2381599f5aa674865743c225f201cc7c..a4adbdae53c0edfe92cfe010d785acae89855c03 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -230,6 +230,10 @@ Library
 - Issue #29218: Unused install_misc command is now removed.  It has been
   documented as unused since 2000.  Patch by Eric N. Vander Weele.
 
+- Issue #29368: The extend() method is now called instead of the append()
+  method when unpickle collections.deque and other list-like objects.
+  This can speed up unpickling to 2 times.
+
 - Issue #29338: The help of a builtin or extension class now includes the
   constructor signature if __text_signature__ is provided for the class.
 
index 19f94dce66730afd19386cb94c933c5f37ba5c6b..996d16ede55cc473f11d92abe3591a417ea9e6c9 100644 (file)
@@ -5807,7 +5807,9 @@ static int
 do_append(UnpicklerObject *self, Py_ssize_t x)
 {
     PyObject *value;
+    PyObject *slice;
     PyObject *list;
+    PyObject *result;
     Py_ssize_t len, i;
 
     len = Py_SIZE(self->stack);
@@ -5818,8 +5820,7 @@ do_append(UnpicklerObject *self, Py_ssize_t x)
 
     list = self->stack->data[x - 1];
 
-    if (PyList_Check(list)) {
-        PyObject *slice;
+    if (PyList_CheckExact(list)) {
         Py_ssize_t list_len;
         int ret;
 
@@ -5832,27 +5833,48 @@ do_append(UnpicklerObject *self, Py_ssize_t x)
         return ret;
     }
     else {
-        PyObject *append_func;
-        _Py_IDENTIFIER(append);
-
-        append_func = _PyObject_GetAttrId(list, &PyId_append);
-        if (append_func == NULL)
-            return -1;
-        for (i = x; i < len; i++) {
-            PyObject *result;
-
-            value = self->stack->data[i];
-            result = _Pickle_FastCall(append_func, value);
-            if (result == NULL) {
-                Pdata_clear(self->stack, i + 1);
-                Py_SIZE(self->stack) = x;
-                Py_DECREF(append_func);
+        PyObject *extend_func;
+        _Py_IDENTIFIER(extend);
+
+        extend_func = _PyObject_GetAttrId(list, &PyId_extend);
+        if (extend_func != NULL) {
+            slice = Pdata_poplist(self->stack, x);
+            if (!slice) {
+                Py_DECREF(extend_func);
                 return -1;
             }
+            result = _Pickle_FastCall(extend_func, slice);
+            Py_DECREF(slice);
+            Py_DECREF(extend_func);
+            if (result == NULL)
+                return -1;
             Py_DECREF(result);
         }
-        Py_SIZE(self->stack) = x;
-        Py_DECREF(append_func);
+        else {
+            PyObject *append_func;
+            _Py_IDENTIFIER(append);
+
+            /* Even if the PEP 307 requires extend() and append() methods,
+               fall back on append() if the object has no extend() method
+               for backward compatibility. */
+            PyErr_Clear();
+            append_func = _PyObject_GetAttrId(list, &PyId_append);
+            if (append_func == NULL)
+                return -1;
+            for (i = x; i < len; i++) {
+                value = self->stack->data[i];
+                result = _Pickle_FastCall(append_func, value);
+                if (result == NULL) {
+                    Pdata_clear(self->stack, i + 1);
+                    Py_SIZE(self->stack) = x;
+                    Py_DECREF(append_func);
+                    return -1;
+                }
+                Py_DECREF(result);
+            }
+            Py_SIZE(self->stack) = x;
+            Py_DECREF(append_func);
+        }
     }
 
     return 0;