https://github.com/python/cpython/commit/73f9de32cc03826902741a8e7babfe99741c243a
commit: 73f9de32cc03826902741a8e7babfe99741c243a
branch: 3.15
author: Miss Islington (bot) <[email protected]>
committer: serhiy-storchaka <[email protected]>
date: 2026-10-22T15:17:28Z
summary:

[3.15] gh-158126: Avoid creating AttributeError for optional Pickler attribute 
lookups (GH-158148) (GH-160251)

(cherry picked from commit e60a9da9919bd55d8abd22bad7b96b5fc8360981)

Co-authored-by: Lazizbek Ergashev <[email protected]>

files:
A Misc/NEWS.d/next/Library/2026-09-25-01-29-55.gh-issue-158126.nWmFnq.rst
M Modules/_pickle.c

diff --git 
a/Misc/NEWS.d/next/Library/2026-09-25-01-29-55.gh-issue-158126.nWmFnq.rst 
b/Misc/NEWS.d/next/Library/2026-09-25-01-29-55.gh-issue-158126.nWmFnq.rst
new file mode 100644
index 00000000000000..82bf49faef56d4
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2026-09-25-01-29-55.gh-issue-158126.nWmFnq.rst
@@ -0,0 +1,3 @@
+Speed up :func:`pickle.dumps` and creating a :class:`pickle.Pickler` by
+avoiding the creation of an :exc:`AttributeError` when looking up the
+optional ``reducer_override`` and ``dispatch_table`` attributes.
diff --git a/Modules/_pickle.c b/Modules/_pickle.c
index 611b091d72e723..c5c9405f35aa98 100644
--- a/Modules/_pickle.c
+++ b/Modules/_pickle.c
@@ -4846,6 +4846,25 @@ persistent_id(PyObject *self, PyObject *obj)
     Py_RETURN_NONE;
 }
 
+static PyObject *Pickler_getattr(PyObject *self, PyObject *name);
+
+/* Like PyObject_GetOptionalAttr(), but avoids creating an AttributeError
+   for a missing attribute.  Must not be used for "persistent_id". */
+static int
+pickler_get_optional_attr(PicklerObject *self, PyObject *name,
+                          PyObject **result)
+{
+    if (Py_TYPE(self)->tp_getattro == Pickler_getattr) {
+        *result = _PyObject_GenericGetAttrWithDict((PyObject *)self, name,
+                                                   NULL, 1);
+        if (*result != NULL) {
+            return 1;
+        }
+        return PyErr_Occurred() ? -1 : 0;
+    }
+    return PyObject_GetOptionalAttr((PyObject *)self, name, result);
+}
+
 static int
 dump(PickleState *state, PicklerObject *self, PyObject *obj)
 {
@@ -4867,8 +4886,8 @@ dump(PickleState *state, PicklerObject *self, PyObject 
*obj)
     Py_XSETREF(self->persistent_id, tmp);
 
     /* Cache the reducer_override method, if it exists. */
-    if (PyObject_GetOptionalAttr((PyObject *)self, &_Py_ID(reducer_override),
-                             &tmp) < 0) {
+    if (pickler_get_optional_attr(self, &_Py_ID(reducer_override),
+                                  &tmp) < 0) {
         goto error;
     }
     Py_XSETREF(self->reducer_override, tmp);
@@ -5148,8 +5167,8 @@ _pickle_Pickler___init___impl(PicklerObject *self, 
PyObject *file,
     self->fast_memo = NULL;
 
     if (self->dispatch_table == NULL) {
-        if (PyObject_GetOptionalAttr((PyObject *)self, &_Py_ID(dispatch_table),
-                                &self->dispatch_table) < 0) {
+        if (pickler_get_optional_attr(self, &_Py_ID(dispatch_table),
+                                      &self->dispatch_table) < 0) {
             goto error;
         }
     }

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to