【问题标题】:Python Embedding in C++ : ImportError: No module named pyfunctionC++ 中的 Python 嵌入:ImportError: No module named pyfunction
【发布时间】:2014-06-30 14:21:59
【问题描述】:

您好,我正在尝试将 python (2.7) 嵌入到 C++ (g++ 4.8.2) 中,因此从 C++ 调用 python 函数。这是python文档中提供的用于嵌入的基本代码:

这是我的文件 call_function.cpp

#include <Python.h>

int main(int argc, char *argv[])
{
    PyObject *pName, *pModule, *pDict, *pFunc;
    PyObject *pArgs, *pValue;
    int i;

    if (argc < 3) {
        fprintf(stderr,"Usage: call pythonfile funcname [args]\n");
        return 1;
    }
   /* char pySearchPath[] = "/usr/include/python2.7";
    Py_SetPythonHome(pySearchPath);*/
    Py_Initialize();
    pName = PyString_FromString(argv[1]);
    /* Error checking of pName left out */

    pModule = PyImport_Import(pName);
    Py_DECREF(pName);

    if (pModule != NULL) {
        pFunc = PyObject_GetAttrString(pModule, argv[2]);
        /* pFunc is a new reference */

        if (pFunc && PyCallable_Check(pFunc)) {
            pArgs = PyTuple_New(argc - 3);
            for (i = 0; i < argc - 3; ++i) {
                pValue = PyInt_FromLong(atoi(argv[i + 3]));
                if (!pValue) {
                    Py_DECREF(pArgs);
                    Py_DECREF(pModule);
                    fprintf(stderr, "Cannot convert argument\n");
                    return 1;
                }
                /* pValue reference stolen here: */
                PyTuple_SetItem(pArgs, i, pValue);
            }
            pValue = PyObject_CallObject(pFunc, pArgs);
            Py_DECREF(pArgs);
            if (pValue != NULL) {
                printf("Result of call: %ld\n", PyInt_AsLong(pValue));
                Py_DECREF(pValue);
            }
            else {
                Py_DECREF(pFunc);
                Py_DECREF(pModule);
                PyErr_Print();
                fprintf(stderr,"Call failed\n");
                return 1;
            }
        }
        else {
            if (PyErr_Occurred())
                PyErr_Print();
            fprintf(stderr, "Cannot find function \"%s\"\n", argv[2]);
        }
        Py_XDECREF(pFunc);
        Py_DECREF(pModule);
    }
    else {
        PyErr_Print();
        fprintf(stderr, "Failed to load \"%s\"\n", argv[1]);
        return 1;
    }
    Py_Finalize();
    return 0;
}

现在我的 python 脚本保存为 pyfunction.py,与 call_function.cpp 放在同一文件夹中。

这是 pyfunction.py :

def multiply(a,b):
    print "Will compute", a, "times", b
    c = 0
    for i in range(0, a):
        c = c + b
    return c

现在使用我正在调用的终端:

$ g++ call_function.cpp -I/usr/include/python2.7 -lpython2.7 -o call_function

(编译成功,没有任何错误) (运行程序)

$ ./call_function pyfunction multiply 2 3

(我收到此错误):

ImportError: No module named pyfunction    
Failed to load "pyfunction"

我不明白这怎么可能。我已按照文档进行操作,但仍然收到错误消息。

pyfunction.py放在同一个目录下怎么找不到。

【问题讨论】:

    标签: python c++


    【解决方案1】:

    将以下内容放在 C/C++ 代码中,紧跟在 Py_Initialize(); 之后

    PyRun_SimpleString("import sys");
    PyRun_SimpleString("sys.path.append(\".\")");
    

    【讨论】:

    • 要么使用PyRun_SimpleString("import sys\n" "import os"); PyRun_SimpleString("sys.path.append( os.path.dirname(os.getcwd()) +'/project_name/')");,要么将你的python文件放入build-...-Debug
    • 这对我来说可以正常工作,取代了对 PYTHONPATH= 的需要。 .此处注释中使用 os.getcwd() 的方法可能更跨平台。
    • 我认为sflee 的答案要好得多,因为 1) 是本地的(没有解释器运行)和 2) 可以保护您免受可能导致非常严重的安全问题的逃避攻击和 python 字符串注入。
    【解决方案2】:

    试试这个:

     $ PYTHONPATH=. ./call_function pyfunction multiply 2 3
    

    如果这不起作用,请尝试在此目录中创建__init__.py 文件,然后重试。

    更新:

    我认为PYTHONPATH 是临时解决方案,用于测试东西。 如果您想在所有嵌入式模块都存在时拥有一个目录,则必须在嵌入式解释器中放入与此等效的内容:

    import sys
    sys.path.insert(0, "./path/to/your/modules/")
    

    您可以在解释器中的 python 或 C 级别上执行此操作。 这将以与PYTHONPATH 非常相似的方式添加搜索路径,但它更持久和优雅(恕我直言)。

    【讨论】:

    • 你能解释一下上面的语句是做什么的吗?
    • 谢谢!以上作品。但是请解释一下这是什么?我会“投票”你的答案,但我什至没有 15 声望大声笑:P
    • 我认为Python的交互版为了方便导入,会将当前目录添加到搜索路径中。嵌入时这不会自动完成,因为目录的无害更改可能会导致执行代码的意外更改。
    • @user3000805,乌尔里希是对的。 Python 正在寻找特定位置的模块(在sys.path 中定义)。您可以添加更多路径,python 将在其中查找模块。其中一种方法是通过名为 PYTHONPATH 的环境变量。
    • @spinus 你能指导我如何使用 PYTHONPATH=。在日食?我的意思是我尝试在源文件夹中使用 init.py,但没有运气。我不知道在哪里指定 PYTHONPATH=。而且,这仅适用于Linux,对吗? Windows 它会失败..
    【解决方案3】:

    大家好,遇到同样问题的人,我找到了解决方案! setenv() 是在 stdlib.h 中定义的函数,用于设置环境变量。只需运行它!

    setenv("PYTHONPATH",".",1);
    

    有关 setenv 的更多信息:

    $ man setenv
    

    一切顺利:) 另外,感谢@spinus

    【讨论】:

      【解决方案4】:

      您也可以尝试将这些代码包含到您的 c 程序中

      Py_Initialize();
      PyObject *sys = PyImport_ImportModule("sys");
      PyObject *path = PyObject_GetAttrString(sys, "path");
      PyList_Append(path, PyUnicode_FromString("."));
      

      Here学习

      【讨论】:

      • 在 Py_LIMITED_API 的情况下,PyRun_SimpleString 函数不可用,设置模块路径变得有点棘手。所以这是添加用户编写的模块路径的完美方式。
      【解决方案5】:

      如果 python 文件不导入任何额外的 python-library,则 spinus 提供的解决方案有效。

      但是,如果一个 python 文件导入了一个额外的库,比如说 numpy,上面的代码崩溃如下:

      :~/programs/python$ ./a.out myModule multiply 4 3
      Traceback (most recent call last):
        File "/home/a/programs/python/myModule.py", line 1, in <module>
          import numpy
      ImportError: No module named 'numpy'
      Failed to load "myModule"
      

      作为备注,从 C 中导入 python-library 不起作用:

      PyObject *pNumpy = PyUnicode_FromString("numpy");
      PyObject *pModuleA = PyImport_Import(pNumpy); 
      

      有人知道如何从依赖于其他一些 python 库的 C python 函数调用吗?

      【讨论】:

      • 问题已解决。 C 编译命令指的是错误的 python 版本。因此, Py_Initialize() 错误地计算了模块搜索默认路径。但是,这可以通过编辑环境变量 PYTHONHOME 来调整。
      • 我必须对 PYTHONHOME 进行哪些更改才能使其正常工作?
      • @Humberto,在您的情况下设置的环境变量是什么?就我而言,我有:/Users/my.name/.pyenv/shims/python 并包含文件:/Users/my.name/.pyenv/versions/2.7.13/envs/ipython2
      【解决方案6】:

      对于遇到此问题的其他人:

      您确定您的 .py 文件位于 C++ 可执行文件所在的同一目录中吗?

      我在 CLion 中编程并忘记了可执行文件位于 cmake-build-debug 中。所以我在项目目录中添加了 .py 文件,毫不奇怪我得到了同样的错误 ImportError。 我将 .py 文件放到 cmake-build-debug 中(默认情况下可执行文件在那里),使用了这个问题的答案,一切正常!

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-03-05
        • 2015-09-10
        • 1970-01-01
        • 2011-04-08
        • 2016-08-09
        • 1970-01-01
        • 2017-02-10
        • 2017-04-15
        相关资源
        最近更新 更多