如何将 C 变量作为变量公开给 Python?

How do I expose a C variable to Python as a variable?

假设在用 C 编写的自定义 python 模块中,我声明变量:

static int module_state;

我的模块中的函数设置了这个变量的状态。如果我想知道 module_state 的值,我可以像这样声明一个 getter 函数:

PyObject * get_module_state(PyObject *self)
{
   return PyLong_FromLong(module_state);
}

在 python (3) 我可以简单地做:

import module
...
state = module.get_module_state()

但是,我想将它公开为一个变量:

import module
state = module.module_state

我查看了 API 中的 PyMemberDefPyGetterSetterDef,但我对如何使用它们公开变量感到困惑。一般来说,我不希望 python 用户能够修改变量。

这个变量的用途与errno非常相似,我想让它尽可能透明地可用。

Can modules have properties the same way that objects can? 中的两个主要建议实际上可以非常“轻松”地翻译成 C。

  1. 模块级 __getattr__。这需要Python 3.7。您只需使用 the normal C API mechanism, PyMethodDef.

    定义一个名为 __getattr__ 的函数

    这个函数会做这样的事情:

    if (PyUnicode_CompareWithASCIIString(arg, "name") == 0) {
        return PyLong_FromLong(your_variable);
    }
    else {
        PyErr_SetObject(PyExc_AttributeError, arg);
        return NULL;
    }
    

    请注意,限制(我认为您可以接受)是该变量将是只读的,因为没有等效的模块 __setattr__

  2. 使用 class 代替模块。这可以是在 C 中定义的 class,PyMemberDef 将 C 变量公开为 属性.

    这可能最适合子模块(例如 main_mod.submod)。这样主模块可以将您的 class 实例添加到 sys.modules 中,例如:

    PyObject *sys_modules = PySys_GetObject("modules");
    PyDict_SetItemString(sys_modules, "main_mod.submod", instance);
    

    我认为这种方法可能比第一种方法麻烦得多,但它可以在 C 中使用。