https://github.com/python/cpython/commit/e60a9da9919bd55d8abd22bad7b96b5fc8360981
commit: e60a9da9919bd55d8abd22bad7b96b5fc8360981
branch: main
author: Lazizbek Ergashev <[email protected]>
committer: serhiy-storchaka <[email protected]>
date: 2026-10-22T14:44:40Z
summary:
gh-158126: Avoid creating AttributeError for optional Pickler attribute lookups
(GH-158148)
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 f37c0a5bba5541..114534dce1b3d4 100644
--- a/Modules/_pickle.c
+++ b/Modules/_pickle.c
@@ -5023,6 +5023,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)
{
@@ -5044,8 +5063,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);
@@ -5342,8 +5361,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]