如何使用 c api 在 python 中实现 Closure?

How to implement Closure in python using c api?

我正在尝试使用 python c api:

实现类似这样的功能
def get_add(x):
    def add(y):
        return x + y
    return add

add5 = get_add(5)
add10 = get_add(10)
add5(12) # 17
add10(12) # 22

模块使用示例:

from mymodule import get_add

add5 = get_add(5)
add10 = get_add(10)
add5(12) # 17
add10(12) # 22

其中 mymodule 是用 c.

写的

我从未真正见过 PyFunction_SetClosure 使用过,但我希望用它来修改现有的 Python 函数对象以更改闭包变量。它可能不适合实现从头开始生成带有闭包的新函数,因为这不会根据 PyFunctionObject 实现(因为它们专门用于处理 Python 字节码等)。

您正在寻找的是具有 __call__ 属性的自定义 C API Python 类型。该类型的构造函数设置闭包,调用属性实现您的函数 add.

我将勾勒出基本方案,但没有兴趣生成完整的工作示例。

首先定义将成为您的 C API 对象的结构:

typedef struct {
   PyObject_HEAD
   int a; // I'm assuming you only want to add ints
} Adder;

接下来定义一个 __init__ 函数来生成该结构(这也可以是 __new__ 函数,但我们现在不要太担心......)

static int
Adder_init(Adder *self, PyObject *args, PyObject *kwds) {
    // parse args and kwds to get the argument "a"
    // ...

    self->a = a;
    return 0;  // success!
};

接下来定义 __call__ 函数来添加

static PyObject*
Adder_call(Adder *self, PyObject *args, PyObject *kwds) {
    // parse args and kwds to get the argument "b"
    // ...

    int result = self->a + b;
    return PyLong_FromLong(result);
};

完成这两个函数后,您需要定义类型对象。同样,这只是在下面勾勒出来:

static PyTypeObject MyObject_Type = {
    PyVarObject_HEAD_INIT(NULL, 0)
    // other fields as needed
    .tp_init = Adder_init,
    .tp_call = Added_call,
};

最终将此类型作为 get_add 公开给 Python,并且您的行为完全符合您的要求。