Skip to content

Commit 539b598

Browse files
committed
gh-158126: Avoid creating AttributeError for optional Pickler attribute lookups
1 parent 80f9aa0 commit 539b598

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
@@ -4839,6 +4839,25 @@ persistent_id(PyObject *self, PyObject *obj)
48394839
Py_RETURN_NONE;
48404840
}
48414841

4842+
static PyObject *Pickler_getattr(PyObject *self, PyObject *name);
4843+
4844+
/* Like PyObject_GetOptionalAttr(), but avoids creating an AttributeError
4845+
for a missing attribute. Must not be used for "persistent_id". */
4846+
static int
4847+
pickler_get_optional_attr(PicklerObject *self, PyObject *name,
4848+
PyObject **result)
4849+
{
4850+
if (Py_TYPE(self)->tp_getattro == Pickler_getattr) {
4851+
*result = _PyObject_GenericGetAttrWithDict((PyObject *)self, name,
4852+
NULL, 1);
4853+
if (*result != NULL) {
4854+
return 1;
4855+
}
4856+
return PyErr_Occurred() ? -1 : 0;
4857+
}
4858+
return PyObject_GetOptionalAttr((PyObject *)self, name, result);
4859+
}
4860+
48424861
static int
48434862
dump(PickleState *state, PicklerObject *self, PyObject *obj)
48444863
{
@@ -4860,8 +4879,8 @@ dump(PickleState *state, PicklerObject *self, PyObject *obj)
48604879
Py_XSETREF(self->persistent_id, tmp);
48614880

48624881
/* Cache the reducer_override method, if it exists. */
4863-
if (PyObject_GetOptionalAttr((PyObject *)self, &_Py_ID(reducer_override),
4864-
&tmp) < 0) {
4882+
if (pickler_get_optional_attr(self, &_Py_ID(reducer_override),
4883+
&tmp) < 0) {
48654884
goto error;
48664885
}
48674886
Py_XSETREF(self->reducer_override, tmp);
@@ -5141,8 +5160,8 @@ _pickle_Pickler___init___impl(PicklerObject *self, PyObject *file,
51415160
self->fast_memo = NULL;
51425161

51435162
if (self->dispatch_table == NULL) {
5144-
if (PyObject_GetOptionalAttr((PyObject *)self, &_Py_ID(dispatch_table),
5145-
&self->dispatch_table) < 0) {
5163+
if (pickler_get_optional_attr(self, &_Py_ID(dispatch_table),
5164+
&self->dispatch_table) < 0) {
51465165
goto error;
51475166
}
51485167
}

0 commit comments

Comments
 (0)