首页 > 解决方案 > 如何将 C 变量作为变量公开给 Python?

问题描述

假设在一个用 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,我想让它尽可能透明地可用。

标签: pythoncpython-3.xpython-c-api

解决方案


模块中的两个主要建议可以像对象一样具有属性吗?实际上可以很“容易”地翻译成 C。

  1. 模块级__getattr__. 这需要 Python 3.7。您只需定义一个__getattr__使用普通 C API 机制调用的函数,PyMethodDef .

    此功能将执行以下操作:

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

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

  2. 使用类而不是模块。这可以是在 C 中定义的类,PyMemberDef将 C 变量作为属性公开。

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

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

    我认为这种方式可能比第一种选择麻烦得多,但它可以在 C 中工作。


推荐阅读