You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Python的C扩展中设置静态类变量?

在Python C扩展中设置静态类变量的方法

你说得太对了!在Python的C扩展API里,PyTypeObject确实没给静态类变量专门留插槽——官方文档里列的那些插槽基本都是管实例的行为、成员这些的。不过别慌,有两种非常实用的办法能搞定这个需求:

方法一:在类初始化完成后添加静态变量

当我们调用PyType_Ready()完成自定义类型的初始化后,就可以直接给类对象本身添加属性,这些属性就会成为静态类变量。

举个具体的代码例子,假设我们要实现一个名为MyClass的Python类,并给它添加一个静态变量static_counter:

#include <Python.h>

// 定义实例结构体
typedef struct {
    PyObject_HEAD
    // 实例成员
    int instance_val;
} MyClassObject;

// 定义类型对象
static PyTypeObject MyClassType = {
    PyVarObject_HEAD_INIT(NULL, 0)
    .tp_name = "myextension.MyClass",
    .tp_basicsize = sizeof(MyClassObject),
    .tp_flags = Py_TPFLAGS_DEFAULT,
    .tp_doc = "My custom class",
    // 这里可以添加其他插槽,比如tp_init、tp_dealloc等
};

// 模块定义
static struct PyModuleDef myextensionmodule = {
    PyModuleDef_HEAD_INIT,
    .m_name = "myextension",
    .m_doc = "Example module with static class variable",
    .m_size = -1,
};

PyMODINIT_FUNC PyInit_myextension(void) {
    PyObject* m;
    // 初始化类型
    if (PyType_Ready(&MyClassType) < 0)
        return NULL;

    m = PyModule_Create(&myextensionmodule);
    if (m == NULL)
        return NULL;

    // 将类添加到模块
    Py_INCREF(&MyClassType);
    if (PyModule_AddObject(m, "MyClass", (PyObject*)&MyClassType) < 0) {
        Py_DECREF(&MyClassType);
        Py_DECREF(m);
        return NULL;
    }

    // 给类添加静态变量static_counter,值为42
    PyObject* static_val = PyLong_FromLong(42);
    if (static_val == NULL) {
        Py_DECREF(m);
        return NULL;
    }
    // 设置类属性
    if (PyObject_SetAttrString((PyObject*)&MyClassType, "static_counter", static_val) < 0) {
        Py_DECREF(static_val);
        Py_DECREF(m);
        return NULL;
    }
    // 因为PyObject_SetAttrString会增加引用,所以这里要释放我们创建的对象
    Py_DECREF(static_val);

    return m;
}

这种方法的好处是简单直观,适合在模块初始化时动态添加静态变量。

方法二:预先填充类型的tp_dict

我们也可以在定义PyTypeObject时,预先创建一个字典并赋值给tp_dict字段,字典里的键值对就会成为类的静态变量。不过这种方式需要注意内存管理,确保字典的引用计数正确。

修改上面的例子,用这种方式实现:

#include <Python.h>

// 定义实例结构体
typedef struct {
    PyObject_HEAD
    int instance_val;
} MyClassObject;

// 预先创建静态变量字典
static PyObject* my_class_dict;

// 定义类型对象
static PyTypeObject MyClassType = {
    PyVarObject_HEAD_INIT(NULL, 0)
    .tp_name = "myextension.MyClass",
    .tp_basicsize = sizeof(MyClassObject),
    .tp_flags = Py_TPFLAGS_DEFAULT,
    .tp_doc = "My custom class",
    .tp_dict = NULL, // 先初始化为NULL,后面再赋值
};

// 模块定义
static struct PyModuleDef myextensionmodule = {
    PyModuleDef_HEAD_INIT,
    .m_name = "myextension",
    .m_doc = "Example module with static class variable",
    .m_size = -1,
};

PyMODINIT_FUNC PyInit_myextension(void) {
    PyObject* m;
    // 创建静态变量字典
    my_class_dict = PyDict_New();
    if (my_class_dict == NULL)
        return NULL;

    // 向字典添加静态变量static_counter
    PyObject* static_val = PyLong_FromLong(42);
    if (static_val == NULL) {
        Py_DECREF(my_class_dict);
        return NULL;
    }
    if (PyDict_SetItemString(my_class_dict, "static_counter", static_val) < 0) {
        Py_DECREF(static_val);
        Py_DECREF(my_class_dict);
        return NULL;
    }
    Py_DECREF(static_val);

    // 将字典赋值给类型的tp_dict
    MyClassType.tp_dict = my_class_dict;

    // 初始化类型
    if (PyType_Ready(&MyClassType) < 0) {
        Py_DECREF(my_class_dict);
        return NULL;
    }

    m = PyModule_Create(&myextensionmodule);
    if (m == NULL) {
        Py_DECREF(my_class_dict);
        return NULL;
    }

    // 添加类到模块
    Py_INCREF(&MyClassType);
    if (PyModule_AddObject(m, "MyClass", (PyObject*)&MyClassType) < 0) {
        Py_DECREF(&MyClassType);
        Py_DECREF(my_class_dict);
        Py_DECREF(m);
        return NULL;
    }

    return m;
}

需要注意的是,tp_dict会在PyType_Ready()被调用时被类型系统接管,所以我们不需要在后续手动释放它(除非初始化失败)。

验证效果

编译这个扩展模块后,在Python里就可以像普通类一样访问静态变量了:

import myextension
print(myextension.MyClass.static_counter) # 输出42

两种方法都能实现静态类变量的需求,你可以根据自己的场景选择——如果需要动态添加(比如根据模块参数调整),选第一种;如果变量是固定的,预先定义字典的方式也很稳妥。

内容的提问来源于stack exchange,提问作者John

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 08:56:15