在另一个应用程序中嵌入python时,如何在子模块(即scipy.optimize.nnls)中导入或调用函数

When embedding python in another application how do I import or call a function in a submodule (i.e. scipy.optimize.nnls)?

本文关键字:scipy optimize nnls 导入 函数 调用 应用程序 另一个 python 模块      更新时间:2023-10-16

首先,我将重申一个问题:当使用python文档和其他资源将Python嵌入C/C++应用程序中时。我发现您可以使用以下方法导入模块

PyObject *pName = PyUnicode_FromString((char*)"scipy");
PyObject *pModule = PyImport_Import(pName); 

但是如果我尝试导入"scipy.optimize"

PyObject *pName = PyUnicode_FromString((char*)"scipy.optimize");
PyObject *pModule = PyImport_Import(pName); 

则程序无法初始化pModule 。如果我再试一次

PyObject *pName = PyUnicode_FromString((char*)"scipy");
PyObject *pModule = PyImport_Import(pName); 
pFunc = PyObject_GetAttrString(pModule, (char*)"optimize.nnls");

我在函数名称中输入optimize的地方,它无法初始化pFunc.如何在子模块中导入或调用函数,即如何调用函数scipy.optimize.nnls?

接下来,我将布置我的代码,以防它有帮助:

/* Relelvant imports
    #include <Python.h>
    #include <numpy/arrayobject.h> 
*/
void nnls::update(const vec& x, const vec& y)
{
    mat B;
    vecToGslVec(x, gslx);
    generateX(X, gslx);
    A = gslMatToMat(X);
    B = A.transpose();
    long double *c_out;
    Py_Initialize();
    PyObject *pName = PyUnicode_FromString((char*)"scipy"); //Issue Here
    check(pName, "pName not initializes.");
    PyObject *pModule = PyImport_Import(pName);
    check(pModule, "pModule not initializes.");
    PyObject *pFunc, *pArgs, *pResult;
    PyArrayObject *pNpArray;
    npy_intp Adims[2]; Adims[0] = A.rows(); Adims[1] = A.cols();
    npy_intp bdim[1];  bdim[0] = y.size();
    if (pModule != NULL) {
        pFunc = PyObject_GetAttrString(pModule, (char*)"optimize.nnls"); //Issue Here
        check(pFunc, "pFunc not initializes.");
        /*program never advances past this point unless I remove this check, 
        in which case I get a segfault, because pFunc is not initialized.*/
        if (pFunc && PyCallable_Check(pFunc)) {
            pArgs = PyTuple_Pack(2,
                PyArray_SimpleNewFromData(2, Adims, NPY_FLOAT, B.data()),
                PyArray_SimpleNewFromData(1, bdim , NPY_FLOAT, 
                    const_cast<double*> (y.data()))
            );
            check(pArgs, "pArgs not initializes.");
            pResult = PyObject_CallObject(pFunc, pArgs);
            check(pResult, "pResult not initializes.");
            pNpArray = reinterpret_cast<PyArrayObject*>(pResult);
            log_info("not PyArray cast");
        }
        Py_DECREF(pFunc);
    }
    Py_DECREF(pModule);
    Py_DECREF(pArgs);
    c_out = reinterpret_cast<long double*>(PyArray_DATA(pNpArray));
    for(size_t i=0; i<order; i++){
        gsl_vector_set(gslc, i, c_out[i]);
    }
    if (pResult != NULL) Py_DECREF(pResult); Py_DECREF(pNpArray);
    Py_Finalize();
}

再次,我的问题在行中

PyObject *pModule = PyImport_Import(pName);

pFunc = PyObject_GetAttrString(pModule, (char*)"optimize.nnls");

如果我设置

pName = PyUnicode_FromString((char*)"scipy.optimize"); 

pFunc = PyObject_GetAttrString(pModule, (char*)"optimize.nnls");

代码无法在这些点初始化这些变量。

因此,最后一次重申我的问题,在这种情况下,如何导入模块scipy.optimize或调用函数optimize.nnls?谢谢。我希望它不会太混乱,如果让我知道,我会澄清。

就像很少使用的内置__import__函数一样,当您PyImport_Import名称scipy.optimize时,导入系统确实加载了scipy.optimize模块,但它返回scipy而不是scipy.optimize。您需要遵循属性链到scipy.optimize.nnls

PyObject *scipy = PyImport_Import(pName);
PyObject *optimize = PyObject_GetAttrString(scipy, "optimize");
PyObject *nnls = PyObject_GetAttrString(optimize, "nnls");

与往常一样,当您完成任何参考资料时,不要忘记Py_DECREF您拥有的任何参考资料。这包括诸如 pName .

首先,我从来没有使用过PyImport_Import()。 我一直使用 PyImport_ImportModule() ,它采用const char *参数而不是PyObject *。 这应该可以节省代码中的一些步骤。

PyObject *pModule = PyImport_ImportModule("scipy.optimize");
PyObject *pFunc = PyObject_GetAttrString(pModule, "nnls");

这就是我在编写的代码中做事的方式。 PyImport_ImportModule()处理包层次结构。 PyObject_getAttrString()不知道如何处理这个点。

我从未使用过PyImport_Import(),所以我不知道它的行为会如何改变事情。