https://github.com/python/cpython/commit/be9b776bde9b51652286c17b33e06d8646b6b3c6
commit: be9b776bde9b51652286c17b33e06d8646b6b3c6
branch: 3.14
author: Miss Islington (bot) <[email protected]>
committer: serhiy-storchaka <[email protected]>
date: 2026-10-22T15:15:00Z
summary:

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

(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 531ec753e9b58f..cba47396a7c280 100644
--- a/Modules/_pickle.c
+++ b/Modules/_pickle.c
@@ -4735,6 +4735,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)
 {
@@ -4756,8 +4775,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);
@@ -5037,8 +5056,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