【问题标题】:How to create and return a function object in a c extension module?如何在 c 扩展模块中创建和返回函数对象?
【发布时间】:2016-08-16 06:27:02
【问题描述】:

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

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

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

【问题讨论】:

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


    【解决方案1】:

    让我们先看看一个可能的 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(&amp;curried_def, args)的第二个参数应该是这个函数绑定的self对象,因此我们会得到一个内置方法元组对象的咖喱。如果您需要原始函数的self 参数或使用关键字参数,则必须稍微扩展此技巧并构建一个自定义对象来传递而不是args。也可以为 curried 函数创建类似 PyCFunction 的类型。据我所知,目前还没有类似的东西。

    【讨论】:

      猜你喜欢
      • 2012-04-04
      • 1970-01-01
      • 1970-01-01
      • 2017-09-24
      • 2022-07-22
      • 2015-04-23
      • 2011-02-25
      • 2017-07-29
      • 1970-01-01
      相关资源
      最近更新 更多