python - 如何在 C 扩展模块中创建并返回函数对象?

标签 python c higher-order-functions python-c-api python-extensions

我正在尝试编写一个 python 扩展模块,其中一些函数被柯里化(Currying),但我不太确定如何去做。主要困难是我不确定如何创建和返回 PyFunction 对象以及如何向其传递其参数的解析规则。有没有一种相当有效的方法来做到这一点,或者这是疯狂的?

从 python 方面来看,所需的语义是:

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

最佳答案

让我们首先看一下可能的 Python 实现。

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

这里唯一需要在 C 中完成的事情是以某种方式创建 lambda 函数。这里我们遇到的问题是不知道 PyCFunction 调用 C 函数本身。因此,我们必须围绕它编写包装器并创建一个新的 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该函数绑定(bind)到的对象,因此我们将得到一个由元组对象柯里化(Currying)的内置方法。如果您需要原始函数的 self 参数或使用关键字参数,则必须稍微扩展此技巧并构建一个自定义对象来传递,而不是传递 args 。还可以为柯里化(Currying)函数创建类似 PyCFunction 的类型。据我所知,还没有这样的事情。

关于python - 如何在 C 扩展模块中创建并返回函数对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36796944/

相关文章:

python - kubectl exec 返回 `Handshake status 500`

c - 下一个 C 标准的想法应该去哪里?

c - 交换数组内的奇数和偶数,C

javascript - 使用高阶函数,如果另一个值为 true,则返回一个对象值 (JavaScript)

python - 带日期的 matplotlib 固定定位器

python - httplib.HTTPSConnection 在并发环境中导致 SSL 错误

Python-按常量列标题排列 CSV 文件的不同行

c - 使用 malloc 探索堆内存

javascript - react : Is it possible to call a higher-order component within a container component?

java - java中使用高阶函数重写抽象方法