3 #include "structmember.h"
5 /* _functools module written and maintained
6 by Hye-Shik Chang <perky@FreeBSD.org>
7 with adaptations by Raymond Hettinger <python@rcn.com>
8 Copyright (c) 2004, 2005, 2006 Python Software Foundation.
12 /* reduce() *************************************************************/
15 functools_reduce(PyObject
*self
, PyObject
*args
)
17 PyObject
*seq
, *func
, *result
= NULL
, *it
;
19 if (!PyArg_UnpackTuple(args
, "reduce", 2, 3, &func
, &seq
, &result
))
24 it
= PyObject_GetIter(seq
);
26 PyErr_SetString(PyExc_TypeError
,
27 "reduce() arg 2 must support iteration");
32 if ((args
= PyTuple_New(2)) == NULL
)
38 if (args
->ob_refcnt
> 1) {
40 if ((args
= PyTuple_New(2)) == NULL
)
44 op2
= PyIter_Next(it
);
54 PyTuple_SetItem(args
, 0, result
);
55 PyTuple_SetItem(args
, 1, op2
);
56 if ((result
= PyEval_CallObject(func
, args
)) == NULL
)
64 PyErr_SetString(PyExc_TypeError
,
65 "reduce() of empty sequence with no initial value");
77 PyDoc_STRVAR(reduce_doc
,
78 "reduce(function, sequence[, initial]) -> value\n\
80 Apply a function of two arguments cumulatively to the items of a sequence,\n\
81 from left to right, so as to reduce the sequence to a single value.\n\
82 For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) calculates\n\
83 ((((1+2)+3)+4)+5). If initial is present, it is placed before the items\n\
84 of the sequence in the calculation, and serves as a default when the\n\
90 /* partial object **********************************************************/
98 PyObject
*weakreflist
; /* List of weak references */
101 static PyTypeObject partial_type
;
104 partial_new(PyTypeObject
*type
, PyObject
*args
, PyObject
*kw
)
109 if (PyTuple_GET_SIZE(args
) < 1) {
110 PyErr_SetString(PyExc_TypeError
,
111 "type 'partial' takes at least one argument");
115 func
= PyTuple_GET_ITEM(args
, 0);
116 if (!PyCallable_Check(func
)) {
117 PyErr_SetString(PyExc_TypeError
,
118 "the first argument must be callable");
122 /* create partialobject structure */
123 pto
= (partialobject
*)type
->tp_alloc(type
, 0);
129 pto
->args
= PyTuple_GetSlice(args
, 1, PY_SSIZE_T_MAX
);
130 if (pto
->args
== NULL
) {
136 pto
->kw
= PyDict_Copy(kw
);
137 if (pto
->kw
== NULL
) {
146 pto
->weakreflist
= NULL
;
149 return (PyObject
*)pto
;
153 partial_dealloc(partialobject
*pto
)
155 PyObject_GC_UnTrack(pto
);
156 if (pto
->weakreflist
!= NULL
)
157 PyObject_ClearWeakRefs((PyObject
*) pto
);
159 Py_XDECREF(pto
->args
);
161 Py_XDECREF(pto
->dict
);
162 Py_TYPE(pto
)->tp_free(pto
);
166 partial_call(partialobject
*pto
, PyObject
*args
, PyObject
*kw
)
169 PyObject
*argappl
= NULL
, *kwappl
= NULL
;
171 assert (PyCallable_Check(pto
->fn
));
172 assert (PyTuple_Check(pto
->args
));
173 assert (pto
->kw
== Py_None
|| PyDict_Check(pto
->kw
));
175 if (PyTuple_GET_SIZE(pto
->args
) == 0) {
178 } else if (PyTuple_GET_SIZE(args
) == 0) {
180 Py_INCREF(pto
->args
);
182 argappl
= PySequence_Concat(pto
->args
, args
);
187 if (pto
->kw
== Py_None
) {
191 kwappl
= PyDict_Copy(pto
->kw
);
192 if (kwappl
== NULL
) {
197 if (PyDict_Merge(kwappl
, kw
, 1) != 0) {
205 ret
= PyObject_Call(pto
->fn
, argappl
, kwappl
);
212 partial_traverse(partialobject
*pto
, visitproc visit
, void *arg
)
221 PyDoc_STRVAR(partial_doc
,
222 "partial(func, *args, **keywords) - new function with partial application\n\
223 of the given arguments and keywords.\n");
225 #define OFF(x) offsetof(partialobject, x)
226 static PyMemberDef partial_memberlist
[] = {
227 {"func", T_OBJECT
, OFF(fn
), READONLY
,
228 "function object to use in future partial calls"},
229 {"args", T_OBJECT
, OFF(args
), READONLY
,
230 "tuple of arguments to future partial calls"},
231 {"keywords", T_OBJECT
, OFF(kw
), READONLY
,
232 "dictionary of keyword arguments to future partial calls"},
233 {NULL
} /* Sentinel */
237 partial_get_dict(partialobject
*pto
)
239 if (pto
->dict
== NULL
) {
240 pto
->dict
= PyDict_New();
241 if (pto
->dict
== NULL
)
244 Py_INCREF(pto
->dict
);
249 partial_set_dict(partialobject
*pto
, PyObject
*value
)
253 /* It is illegal to del p.__dict__ */
255 PyErr_SetString(PyExc_TypeError
,
256 "a partial object's dictionary may not be deleted");
259 /* Can only set __dict__ to a dictionary */
260 if (!PyDict_Check(value
)) {
261 PyErr_SetString(PyExc_TypeError
,
262 "setting partial object's dictionary to a non-dict");
272 static PyGetSetDef partial_getsetlist
[] = {
273 {"__dict__", (getter
)partial_get_dict
, (setter
)partial_set_dict
},
274 {NULL
} /* Sentinel */
278 __reduce__ by itself doesn't support getting kwargs in the unpickle
279 operation so we define a __setstate__ that replaces all the information
280 about the partial. If we only replaced part of it someone would use
281 it as a hook to do stange things.
285 partial_reduce(partialobject
*pto
, PyObject
*unused
)
287 return Py_BuildValue("O(O)(OOOO)", Py_TYPE(pto
), pto
->fn
, pto
->fn
,
289 pto
->dict
? pto
->dict
: Py_None
);
293 partial_setstate(partialobject
*pto
, PyObject
*args
)
295 PyObject
*fn
, *fnargs
, *kw
, *dict
;
296 if (!PyArg_ParseTuple(args
, "(OOOO):__setstate__",
297 &fn
, &fnargs
, &kw
, &dict
))
300 Py_XDECREF(pto
->args
);
302 Py_XDECREF(pto
->dict
);
306 if (dict
!= Py_None
) {
318 static PyMethodDef partial_methods
[] = {
319 {"__reduce__", (PyCFunction
)partial_reduce
, METH_NOARGS
},
320 {"__setstate__", (PyCFunction
)partial_setstate
, METH_VARARGS
},
321 {NULL
, NULL
} /* sentinel */
324 static PyTypeObject partial_type
= {
325 PyVarObject_HEAD_INIT(NULL
, 0)
326 "functools.partial", /* tp_name */
327 sizeof(partialobject
), /* tp_basicsize */
330 (destructor
)partial_dealloc
, /* tp_dealloc */
336 0, /* tp_as_number */
337 0, /* tp_as_sequence */
338 0, /* tp_as_mapping */
340 (ternaryfunc
)partial_call
, /* tp_call */
342 PyObject_GenericGetAttr
, /* tp_getattro */
343 PyObject_GenericSetAttr
, /* tp_setattro */
344 0, /* tp_as_buffer */
345 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_HAVE_GC
|
346 Py_TPFLAGS_BASETYPE
| Py_TPFLAGS_HAVE_WEAKREFS
, /* tp_flags */
347 partial_doc
, /* tp_doc */
348 (traverseproc
)partial_traverse
, /* tp_traverse */
350 0, /* tp_richcompare */
351 offsetof(partialobject
, weakreflist
), /* tp_weaklistoffset */
354 partial_methods
, /* tp_methods */
355 partial_memberlist
, /* tp_members */
356 partial_getsetlist
, /* tp_getset */
359 0, /* tp_descr_get */
360 0, /* tp_descr_set */
361 offsetof(partialobject
, dict
), /* tp_dictoffset */
364 partial_new
, /* tp_new */
365 PyObject_GC_Del
, /* tp_free */
369 /* module level code ********************************************************/
371 PyDoc_STRVAR(module_doc
,
372 "Tools that operate on functions.");
374 static PyMethodDef module_methods
[] = {
375 {"reduce", functools_reduce
, METH_VARARGS
, reduce_doc
},
376 {NULL
, NULL
} /* sentinel */
385 PyTypeObject
*typelist
[] = {
390 m
= Py_InitModule3("_functools", module_methods
, module_doc
);
394 for (i
=0 ; typelist
[i
] != NULL
; i
++) {
395 if (PyType_Ready(typelist
[i
]) < 0)
397 name
= strchr(typelist
[i
]->tp_name
, '.');
398 assert (name
!= NULL
);
399 Py_INCREF(typelist
[i
]);
400 PyModule_AddObject(m
, name
+1, (PyObject
*)typelist
[i
]);