[Python-checkins] cpython: Issue #29368: The extend() method is now called instead of the append()

serhiy.storchaka python-checkins at python.org
Thu Feb 2 04:13:13 EST 2017


https://hg.python.org/cpython/rev/94d630a02a81
changeset:   106380:94d630a02a81
parent:      106377:762a93935afd
user:        Serhiy Storchaka <storchaka at gmail.com>
date:        Thu Feb 02 11:12:47 2017 +0200
summary:
  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.

files:
  Lib/pickle.py     |  17 +++++++--
  Misc/NEWS         |   4 ++
  Modules/_pickle.c |  60 +++++++++++++++++++++++-----------
  3 files changed, 57 insertions(+), 24 deletions(-)


diff --git a/Lib/pickle.py b/Lib/pickle.py
--- a/Lib/pickle.py
+++ b/Lib/pickle.py
@@ -1464,12 +1464,19 @@
     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):
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -230,6 +230,10 @@
 - 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.
 
diff --git a/Modules/_pickle.c b/Modules/_pickle.c
--- a/Modules/_pickle.c
+++ b/Modules/_pickle.c
@@ -5807,7 +5807,9 @@
 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 @@
 
     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 @@
         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;

-- 
Repository URL: https://hg.python.org/cpython


More information about the Python-checkins mailing list