Skip to content

Commit a107cf0

Browse files
committed
Make built-in methods picklable through the reduce protocol.
1 parent 4bde55f commit a107cf0

3 files changed

Lines changed: 22 additions & 41 deletions

File tree

Lib/pickle.py

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
2424
"""
2525

26-
from types import FunctionType, BuiltinFunctionType, ModuleType
26+
from types import FunctionType, ModuleType
2727
from copyreg import dispatch_table
2828
from copyreg import _extension_registry, _inverted_registry, _extension_cache
2929
from itertools import islice
@@ -962,14 +962,7 @@ def save_global(self, obj, name=None):
962962

963963
self.memoize(obj)
964964

965-
def save_method(self, obj):
966-
if obj.__self__ is None or type(obj.__self__) is ModuleType:
967-
self.save_global(obj)
968-
else:
969-
self.save_reduce(getattr, (obj.__self__, obj.__name__), obj=obj)
970-
971965
dispatch[FunctionType] = save_global
972-
dispatch[BuiltinFunctionType] = save_method
973966
dispatch[type] = save_global
974967

975968

Modules/_pickle.c

Lines changed: 0 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -3513,34 +3513,6 @@ save_reduce(PicklerObject *self, PyObject *args, PyObject *obj)
35133513
return 0;
35143514
}
35153515

3516-
static int
3517-
save_method(PicklerObject *self, PyObject *obj)
3518-
{
3519-
PyObject *method_self = PyCFunction_GET_SELF(obj);
3520-
3521-
if (method_self == NULL || PyModule_Check(method_self)) {
3522-
return save_global(self, obj, NULL);
3523-
}
3524-
else {
3525-
PyObject *builtins;
3526-
PyObject *getattr;
3527-
PyObject *reduce_value;
3528-
int status = -1;
3529-
_Py_IDENTIFIER(getattr);
3530-
3531-
builtins = PyEval_GetBuiltins();
3532-
getattr = _PyDict_GetItemId(builtins, &PyId_getattr);
3533-
reduce_value = \
3534-
Py_BuildValue("O(Os)", getattr, method_self,
3535-
((PyCFunctionObject *)obj)->m_ml->ml_name);
3536-
if (reduce_value != NULL) {
3537-
status = save_reduce(self, reduce_value, obj);
3538-
Py_DECREF(reduce_value);
3539-
}
3540-
return status;
3541-
}
3542-
}
3543-
35443516
static int
35453517
save(PicklerObject *self, PyObject *obj, int pers_save)
35463518
{
@@ -3652,10 +3624,6 @@ save(PicklerObject *self, PyObject *obj, int pers_save)
36523624
goto done;
36533625
}
36543626
}
3655-
else if (type == &PyCFunction_Type) {
3656-
status = save_method(self, obj);
3657-
goto done;
3658-
}
36593627

36603628
/* XXX: This part needs some unit tests. */
36613629

Objects/methodobject.c

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,26 @@ meth_dealloc(PyCFunctionObject *m)
159159
}
160160
}
161161

162+
static PyObject *
163+
meth_reduce(PyCFunctionObject *m)
164+
{
165+
PyObject *builtins;
166+
PyObject *getattr;
167+
_Py_IDENTIFIER(getattr);
168+
169+
if (m->m_self == NULL || PyModule_Check(m->m_self))
170+
return PyUnicode_FromString(m->m_ml->ml_name);
171+
172+
builtins = PyEval_GetBuiltins();
173+
getattr = _PyDict_GetItemId(builtins, &PyId_getattr);
174+
return Py_BuildValue("O(Os)", getattr, m->m_self, m->m_ml->ml_name);
175+
}
176+
177+
static PyMethodDef meth_methods[] = {
178+
{"__reduce__", (PyCFunction)meth_reduce, METH_NOARGS, NULL},
179+
{NULL, NULL}
180+
};
181+
162182
/*
163183
* finds the docstring's introspection signature.
164184
* if present, returns a pointer pointing to the first '('.
@@ -394,7 +414,7 @@ PyTypeObject PyCFunction_Type = {
394414
0, /* tp_weaklistoffset */
395415
0, /* tp_iter */
396416
0, /* tp_iternext */
397-
0, /* tp_methods */
417+
meth_methods, /* tp_methods */
398418
meth_members, /* tp_members */
399419
meth_getsets, /* tp_getset */
400420
0, /* tp_base */

0 commit comments

Comments
 (0)