0

我想写一个python扩展模块,其中的一些功能是curried,但我不太确定如何去做这件事。主要困难在于我不确定如何创建并返回一个PyFunction对象,以及如何将其参数的解析规则传递给它。有没有一个相当有效的方法来做到这一点,或者是这种疯狂?如何在c扩展模块中创建并返回一个函数对象?

从Python方所需的语义是:

# given a function f(x, y) 
f(a, b) -> result 
f(a) -> f' 
f'(b) -> result 

回答

1

让我们来看看一个可能的Python实现第一。

def f(x, y=None): 
    if y is None: 
     return lambda y: f(x, y) 
    return 'result' 

这就需要用C做此以某种方式创建lambda功能的唯一的事。在这里,我们不知道调用C函数本身的PyCFunction的问题。所以我们必须编写一个包装器并创建一个新的PyCFunction对象。

static PyObject* curried (PyObject *old_args, PyObject *new_args); 
static PyMethodDef curried_def = {"curried", curried, METH_VARARGS, "curried"}; 

static PyObject* f (PyObject *self, PyObject *args) { 
    PyObject *x = NULL, *y = NULL; 
    if(!PyArg_ParseTuple(args, "O|O", &x, &y)) 
     return NULL; 

    // validate x 
    if (y == NULL) 
     return Py_INCREF(args), PyCFunction_New(&curried_def, args); 
    // validate y 

    // do something to obtain the result 
    return result; 
} 

static PyObject* curried (PyObject *old_args, PyObject *new_args) { 
    Py_ssize_t old_args_count = PyTuple_Size(old_args); 
    Py_ssize_t new_args_count = PyTuple_Size(new_args); 
    PyObject *all_args = PyTuple_New(old_args_count + new_args_count); 
    Py_ssize_t i; 
    PyObject *o; 
    for (i = 0; i < old_args_count; i++) { 
     o = PyTuple_GET_ITEM(old_args, i); 
     Py_INCREF(o); 
     PyTuple_SET_ITEM(all_args, i, o); 
    } 
    for (i = 0; i < new_args_count; i++) { 
     o = PyTuple_GET_ITEM(new_args, i); 
     Py_INCREF(o); 
     PyTuple_SET_ITEM(all_args, old_args_count + i, o); 
    } 
    return f(NULL, all_args); 
} 

这产生

f(a, b) -> result 
f(a) -> <built-in method curried of tuple object at 0x123456> 
f(a)(b) -> result 

在这里,我们滥用PyCFunction类型一点并传递给PyCFunction_New(&curried_def, args)第二参数所需的语义被认为是该功能被绑定到self对象,因此我们将会得到一个元组对象的内置方法,其元组对象为。如果您需要原始函数的self参数或使用关键字参数,则必须稍微扩展一下这个hack,然后构建一个自定义对象来代替args。也可以为咖喱功能创建一个类似PyCFunction的类型。据我所知,目前还没有这样的事情。

相关问题