当使用 c_types 将 C++ 库打包成共享库 (libSome.so) 以便在 Python 中使用时,调用库中 Python 类的某个方法会产生段错误。问题出现在 Python 的方法调用机制上。
2. 解决方案
(1) 问题在于尝试使用 PyObject_CallMethod() 调用 Python 方法时,没有传递正确的参数类型。
(2) 正确的调用应该使用 PyObject_CallObject(),它允许传递任意类型和数量的参数。
(3) 此外,需要确保 C++ 代码中传递给 Python 方法的参数与 Python 方法定义中的参数类型相匹配,即 long long -> long,long -> int,double -> float。
(4) 还需要确保 Python 方法的名称与 C++ 代码中尝试调用的名称完全一致,并在 C++ 代码中正确设置环境变量 PYTHONPATH,指向包含 Python 脚本的目录。
以下是修改后的 C++ 代码:
...
/* Funcion de python */
setenv("PYTHONPATH", ".", 1);
Py_Initialize();
PyObject* module = PyImport_ImportModule("filehandler");
assert(module != NULL);
PyObject* class = PyObject_GetAttrString(module, "FileHandler");
assert(class != NULL);
PyObject* inst = PyInstance_New(class, NULL, NULL);
assert(inst != NULL);
PyObject* result = PyObject_CallObject(inst, PyTuple_Pack(4, PyInt_FromLong(ori), PyInt_FromLong(serv), PyInt_FromLong(id), PyFloat_FromDouble(timeStamp)));
assert(result != NULL);
Py_Finalize();
代码例子
Python 代码:
class FileHandler:
def __init__(self):
self.workingDirectory = os.getcwd()
def write(self, NodoOrigen, Servicio, Id, payload):
try:
os.mkdir(str(NodoOrigen))
except:
pass
os.chdir(str(NodoOrigen) + "/")
try:
os.mkdir(str(Servicio))
except:
pass
os.chdir(self.workingDirectory)
os.chdir(str(NodoOrigen) + "/" + str(Servicio) + "/")
try:
f = open(str(Id), "a")
except:
print("No se puede abrir el archivo")
f.write(str(payload))
f.close()
os.chdir(self.workingDirectory)
C++ 代码:
#include <Python.h>
...
int main() {
...
// Initialize Python
Py_Initialize();
// Import the Python module
PyObject* module = PyImport_ImportModule("filehandler");
if (module == NULL) {
PyErr_Print();
return 1;
}
// Get the Python class
PyObject* class = PyObject_GetAttrString(module, "FileHandler");
if (class == NULL) {
PyErr_Print();
return 1;
}
// Create an instance of the Python class
PyObject* instance = PyInstance_New(class, NULL, NULL);
if (instance == NULL) {
PyErr_Print();
return 1;
}
// Call the Python method
PyObject* args = PyTuple_Pack(4, PyLong_FromLong(1), PyLong_FromLong(2), PyLong_FromLong(3), PyFloat_FromDouble(4.5));
if (args == NULL) {
PyErr_Print();
return 1;
}
PyObject* result = PyObject_CallObject(instance, args);
if (result == NULL) {
PyErr_Print();
return 1;
}
// Clean up
Py_DECREF(result);
Py_DECREF(args);
Py_DECREF(instance);
Py_DECREF(class);
Py_DECREF(module);
Py_Finalize();
return 0;
}