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

C++嵌入Python:求通过对象名获取PyObject的Python C API函数

问题:在C++嵌入Python时,如何给PyObject设置名称并通过名称获取?

我正在将Python嵌入到C++中,创建PyObject来表示各类数据/对象(如int、double、string等)。我花费数小时寻找可通过对象名返回PyObject的Python C API函数,原本预期存在可设置并引用Python脚本中全局/局部对象标准名称的name属性或name()方法,甚至设想存在如下函数:

PyObject *PyObject_ByName(PyObject *PyObjs, char* name)

Return value: New reference. Part of the Stable ABI.
Return a new PyObject reference from an array of PyObjs that match the 'name', or NULL on failure.

但并未找到相关内容,我遗漏了什么?目前已完成其他相关代码编写,如下:

MSEXPORT PyObject* PyVariant(VarObj* data, tLvVarErr* error) {
    PyObject* module_name, * module, * dict, * python_class, * object;

    PyObject *pValue = NULL; // <- what I want to set name
    switch (data->data.index())
    {
    case VarIdx::I32:
        pValue = PyLong_FromLong((long) get<int32_t>(data->data));
        break;
    case VarIdx::DBL:
        pValue = PyFloat_FromDouble ((double) get<double>(data->data));
        break;
    case VarIdx::Str :
        pValue = PyUnicode_FromString((char*) get<string*>(data->data)->c_str());
        break;
    default:
        return NULL;
    }
    return pValue;
}

我希望给创建的pValue设置名称,并通过名称获取对应的PyObject,请问相关的Python C API函数是什么?


解决方案

核心逻辑:用字典存储名称与PyObject的映射

Python的基础内置类型(如int/float/str)本身并没有name属性,无法直接给单个PyObject绑定名称。要实现“通过名称查找对象”的需求,需借助**Python字典(PyDict)**维护名称到对象的键值对,这也是Python脚本全局/局部命名空间的底层实现逻辑。

相关Python C API函数

  • 创建字典:PyDict_New()
    生成空字典用于存储映射关系,示例:

    PyObject* name_map = PyDict_New();
    
  • 添加名称-对象映射:PyDict_SetItemString()
    以字符串为键,将PyObject存入字典,函数签名:int PyDict_SetItemString(PyObject *p, const char *key, PyObject *val)
    示例:

    PyDict_SetItemString(name_map, "my_integer", pValue);
    

    注意:该函数会自动增加val的引用计数,无需手动调用Py_INCREF。

  • 通过名称获取对象:PyDict_GetItemString()
    根据字符串键查找对应PyObject,返回借用引用,需调用Py_INCREF转为新引用避免对象被意外释放,函数签名:PyObject* PyDict_GetItemString(PyObject *p, const char *key)
    示例:

    PyObject* retrieved_obj = PyDict_GetItemString(name_map, "my_integer");
    if (retrieved_obj != NULL) {
        Py_INCREF(retrieved_obj);
        // 使用对象逻辑...
    }
    
  • 释放字典:不再使用时调用Py_DECREF(name_map),字典会自动管理内部存储的PyObject引用计数。

整合到你的代码示例

可在调用PyVariant的地方维护全局/局部字典,或修改函数接收名称参数:

// 全局维护的名称映射字典
PyObject* g_name_map = PyDict_New();

MSEXPORT PyObject* PyVariant(VarObj* data, const char* obj_name, tLvVarErr* error) {
    PyObject *pValue = NULL;
    switch (data->data.index())
    {
    case VarIdx::I32:
        pValue = PyLong_FromLong((long) get<int32_t>(data->data));
        break;
    case VarIdx::DBL:
        pValue = PyFloat_FromDouble ((double) get<double>(data->data));
        break;
    case VarIdx::Str :
        pValue = PyUnicode_FromString((char*) get<string*>(data->data)->c_str());
        break;
    default:
        return NULL;
    }
    // 绑定名称到对象
    if (obj_name != NULL && pValue != NULL) {
        PyDict_SetItemString(g_name_map, obj_name, pValue);
    }
    return pValue;
}

// 通过名称获取对象的工具函数
PyObject* GetPyObjectByName(const char* obj_name) {
    PyObject* obj = PyDict_GetItemString(g_name_map, obj_name);
    if (obj != NULL) {
        Py_INCREF(obj);
    }
    return obj;
}

额外说明

如果要将对象注入Python脚本的全局命名空间,可直接操作模块的__dict__属性:

// 获取__main__模块的全局字典
PyObject* main_module = PyImport_AddModule("__main__");
PyObject* global_dict = PyModule_GetDict(main_module);
// 将对象添加到全局命名空间,Python脚本可直接通过名称访问
PyDict_SetItemString(global_dict, "my_var", pValue);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 20:35:16