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 */
277 static PyTypeObject partial_type
= {
278 PyVarObject_HEAD_INIT(NULL
, 0)
279 "functools.partial", /* tp_name */
280 sizeof(partialobject
), /* tp_basicsize */
283 (destructor
)partial_dealloc
, /* tp_dealloc */
289 0, /* tp_as_number */
290 0, /* tp_as_sequence */
291 0, /* tp_as_mapping */
293 (ternaryfunc
)partial_call
, /* tp_call */
295 PyObject_GenericGetAttr
, /* tp_getattro */
296 PyObject_GenericSetAttr
, /* tp_setattro */
297 0, /* tp_as_buffer */
298 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_HAVE_GC
|
299 Py_TPFLAGS_BASETYPE
| Py_TPFLAGS_HAVE_WEAKREFS
, /* tp_flags */
300 partial_doc
, /* tp_doc */
301 (traverseproc
)partial_traverse
, /* tp_traverse */
303 0, /* tp_richcompare */
304 offsetof(partialobject
, weakreflist
), /* tp_weaklistoffset */
308 partial_memberlist
, /* tp_members */
309 partial_getsetlist
, /* tp_getset */
312 0, /* tp_descr_get */
313 0, /* tp_descr_set */
314 offsetof(partialobject
, dict
), /* tp_dictoffset */
317 partial_new
, /* tp_new */
318 PyObject_GC_Del
, /* tp_free */
322 /* module level code ********************************************************/
324 PyDoc_STRVAR(module_doc
,
325 "Tools that operate on functions.");
327 static PyMethodDef module_methods
[] = {
328 {"reduce", functools_reduce
, METH_VARARGS
, reduce_doc
},
329 {NULL
, NULL
} /* sentinel */
338 PyTypeObject
*typelist
[] = {
343 m
= Py_InitModule3("_functools", module_methods
, module_doc
);
347 for (i
=0 ; typelist
[i
] != NULL
; i
++) {
348 if (PyType_Ready(typelist
[i
]) < 0)
350 name
= strchr(typelist
[i
]->tp_name
, '.');
351 assert (name
!= NULL
);
352 Py_INCREF(typelist
[i
]);
353 PyModule_AddObject(m
, name
+1, (PyObject
*)typelist
[i
]);