summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSerhiy Storchaka <storchaka@gmail.com>2017-02-02 11:12:47 +0200
committerSerhiy Storchaka <storchaka@gmail.com>2017-02-02 11:12:47 +0200
commit15a16320c91ea7be43a7b0adebd83f39e20b8392 (patch)
tree70d2c080d0b22bd62189466a2ffe57f040181ef2
parent4a0593e451159f1292921fa9068acae2639766bf (diff)
downloadcpython-15a16320c91ea7be43a7b0adebd83f39e20b8392.tar.gz
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.
-rw-r--r--Lib/pickle.py17
-rw-r--r--Misc/NEWS4
-rw-r--r--Modules/_pickle.c60
3 files changed, 57 insertions, 24 deletions
diff --git a/Lib/pickle.py b/Lib/pickle.py
index c8370c9f7e..702b0b35ce 100644
--- a/Lib/pickle.py
+++ b/Lib/pickle.py
@@ -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):
diff --git a/Misc/NEWS b/Misc/NEWS
index 21685d3a23..a4adbdae53 100644
--- 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.
diff --git a/Modules/_pickle.c b/Modules/_pickle.c
index 19f94dce66..996d16ede5 100644
--- a/Modules/_pickle.c
+++ b/Modules/_pickle.c
@@ -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;