Skip to content

Commit e60a9da

Browse files
authored
gh-158126: Avoid creating AttributeError for optional Pickler attribute lookups (GH-158148)
1 parent e67334a commit e60a9da

2 files changed

Lines changed: 26 additions & 4 deletions

File tree

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Speed up :func:`pickle.dumps` and creating a :class:`pickle.Pickler` by
2+
avoiding the creation of an :exc:`AttributeError` when looking up the
3+
optional ``reducer_override`` and ``dispatch_table`` attributes.

‎Modules/_pickle.c‎

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5023,6 +5023,25 @@ persistent_id(PyObject *self, PyObject *obj)
50235023
Py_RETURN_NONE;
50245024
}
50255025

5026+
static PyObject *Pickler_getattr(PyObject *self, PyObject *name);
5027+
5028+
/* Like PyObject_GetOptionalAttr(), but avoids creating an AttributeError
5029+
for a missing attribute. Must not be used for "persistent_id". */
5030+
static int
5031+
pickler_get_optional_attr(PicklerObject *self, PyObject *name,
5032+
PyObject **result)
5033+
{
5034+
if (Py_TYPE(self)->tp_getattro == Pickler_getattr) {
5035+
*result = _PyObject_GenericGetAttrWithDict((PyObject *)self, name,
5036+
NULL, 1);
5037+
if (*result != NULL) {
5038+
return 1;
5039+
}
5040+
return PyErr_Occurred() ? -1 : 0;
5041+
}
5042+
return PyObject_GetOptionalAttr((PyObject *)self, name, result);
5043+
}
5044+
50265045
static int
50275046
dump(PickleState *state, PicklerObject *self, PyObject *obj)
50285047
{
@@ -5044,8 +5063,8 @@ dump(PickleState *state, PicklerObject *self, PyObject *obj)
50445063
Py_XSETREF(self->persistent_id, tmp);
50455064

50465065
/* Cache the reducer_override method, if it exists. */
5047-
if (PyObject_GetOptionalAttr((PyObject *)self, &_Py_ID(reducer_override),
5048-
&tmp) < 0) {
5066+
if (pickler_get_optional_attr(self, &_Py_ID(reducer_override),
5067+
&tmp) < 0) {
50495068
goto error;
50505069
}
50515070
Py_XSETREF(self->reducer_override, tmp);
@@ -5342,8 +5361,8 @@ _pickle_Pickler___init___impl(PicklerObject *self, PyObject *file,
53425361
self->fast_memo = NULL;
53435362

53445363
if (self->dispatch_table == NULL) {
5345-
if (PyObject_GetOptionalAttr((PyObject *)self, &_Py_ID(dispatch_table),
5346-
&self->dispatch_table) < 0) {
5364+
if (pickler_get_optional_attr(self, &_Py_ID(dispatch_table),
5365+
&self->dispatch_table) < 0) {
53475366
goto error;
53485367
}
53495368
}

0 commit comments

Comments
 (0)