8000 use PyObject_TypeCheck in the C implementation of partial.__new__ · python/cpython@97b9966 · GitHub
[go: up one dir, main page]

Skip to content

Commit 97b9966

Browse files
committed
use PyObject_TypeCheck in the C implementation of partial.__new__
1 parent 30557a1 commit 97b9966

File tree

3 files changed

+15
-6
lines changed

3 files changed

+15
-6
lines changed

Lib/functools.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,7 @@ def __new__(cls, func, /, *args, **keywords):
284284
if not callable(func):
285285
raise TypeError("the first argument must be callable")
286286

287-
if isinstance(func, partial) and hasattr(func, "func"):
287+
if isinstance(func, partial):
288288
args = func.args + args
289289
keywords = {**func.keywords, **keywords}
290290
func = func.func
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ 8000 -1,3 +1,5 @@
11
Bring pure Python implementation ``functools.partial.__new__`` more in line
22
with the C-implementation by not just always checking for the presence of
3-
the attribute ``'func'`` on the first argument of ``partial``.
3+
the attribute ``'func'`` on the first argument of ``partial``. Instead, both
4+
the Python version and the C version perform an ``isinstance(func, partial)``
5+
check on the first argument of ``partial``.

Modules/_functoolsmodule.c

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,12 +79,19 @@ partial_new(PyTypeObject *type, PyObject *args, PyObject *kw)
7979
return NULL;
8080
}
8181

82+
_functools_state *state = get_functools_state_by_type(type);
83+
if (state == NULL) {
84+
return NULL;
85+
}
86+
8287
pargs = pkw = NULL;
8388
func = PyTuple_GET_ITEM(args, 0);
84-
if (Py_TYPE(func)->tp_call == (ternaryfunc)partial_call) {
85-
// The type of "func" might not be exactly the same type object
86-
// as "type", but if it is called using partial_call, it must have the
87-
// same memory layout (fn, args and kw members).
89+
90+
int res = PyObject_TypeCheck(func, state->partial_type);
91+
if (res == -1) {
92+
return NULL;
93+
}
94+
if (res == 1) {
8895
// We can use its underlying function directly and merge the arguments.
8996
partialobject *part = (partialobject *)func;
9097
if (part->dict == NULL) {

0 commit comments

Comments
 (0)
0