C++嵌入Python:求通过对象名获取PyObject的Python C API函数
我正在将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

