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

如何在Python C扩展模块中创建自定义类型的静态对象

实现方案

首先修正现有代码的类型不匹配问题,再完成实例字段填充和列表导出:

1. 修正自定义类型的成员定义

你当前Country结构体的name、capital是char*类型,但PyMemberDef中指定的T_OBJECT_EX对应PyObject*类型,二者不匹配会导致内存访问错误。我们调整为存储Python字符串对象,符合Python扩展的常规实现:

typedef struct {
    PyObject_HEAD
    PyObject *name; // 改为PyObject*存储Python字符串
    PyObject *capital;
} Country;

static struct PyMemberDef CountryMembers[] = {
    {"name", T_OBJECT_EX, offsetof(Country, name), 0, "国家名称"},
    {"capital", T_OBJECT_EX, offsetof(Country, capital), 0, "首都名称"},
    {NULL}
};

// 补充析构函数避免内存泄漏
static void Country_dealloc(Country* self) {
    Py_XDECREF(self->name);
    Py_XDECREF(self->capital);
    Py_TYPE(self)->tp_free((PyObject*)self);
}

static PyTypeObject CountryType = {
    PyVarObject_HEAD_INIT(NULL, 0)
    .tp_name = "countries.Country",
    .tp_doc = "国家信息类型",
    .tp_basicsize = sizeof(Country),
    .tp_itemsize = 0,
    .tp_flags = Py_TPFLAGS_DEFAULT,
    .tp_new = PyType_GenericNew,
    .tp_members = CountryMembers,
    .tp_dealloc = (destructor)Country_dealloc, // 注册析构函数
};

2. 实例化自定义类型并填充字段

创建实例后,可以直接通过结构体指针操作成员,执行效率更高:

// 模块初始化函数内的代码
// 1. 创建存储所有国家的列表
PyObject *countries_list = PyList_New(0);
if (!countries_list) {
    return NULL;
}

// 2. 创建Country实例并填充字段
Country *afghanistan = (Country*)PyObject_CallObject((PyObject*)&CountryType, NULL);
if (!afghanistan) {
    Py_DECREF(countries_list);
    return NULL;
}
// 填充字段:将C字符串转为Python Unicode对象赋值给结构体成员
afghanistan->name = PyUnicode_FromString("Afghanistan");
afghanistan->capital = PyUnicode_FromString("Kabul");

// 3. 将实例添加到国家列表
PyList_Append(countries_list, (PyObject*)afghanistan);
// 列表已经持有实例引用,释放局部引用避免内存泄漏
Py_DECREF(afghanistan);

// 可按照上述逻辑批量添加其他国家实例

// 4. 将国家列表注册为模块导出成员
PyModule_AddObject(local_module, "countries", countries_list);

3. 可选通用属性设置方案

如果你不想依赖结构体的内部定义,也可以用Python对象通用属性设置API实现字段填充,不需要强制转换结构体指针:

PyObject *afghanistan = PyObject_CallObject((PyObject*)&CountryType, NULL);
PyObject_SetAttrString(afghanistan, "name", PyUnicode_FromString("Afghanistan"));
PyObject_SetAttrString(afghanistan, "capital", PyUnicode_FromString("Kabul"));

这种方式更适合跨模块调用自定义类型的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 12:06:03