为什么在导入C++中的模块后,我无法访问我的Python函数?

2024-09-27 20:18:48 发布

您现在位置:Python中文网/ 问答频道 /正文

我试图调用一个函数^ {CD1>},它是C++中的用户定义的Python模块^ {< CD2>}类^ {CD2>}的成员

#define PY_SSIZE_T_CLEAN
#include <Python.h>

int main()
{
    Py_Initialize();

    //modify python module search path
    auto modulePath = /* hardcoded search path for module */
    PyObject* sysPath = PySys_GetObject("path");
    PyList_Append(sysPath, PyUnicode_FromString(modulePath));

    PyObject* pModule = PyImport_ImportModule("Spam");
    PyObject* pDict = PyModule_GetDict(pModule);
    PyObject* pFunc = PyObject_GetAttrString(pDict, "print_stuff");
    
    if (pFunc != NULL)
        PyObject_CallObject(pFunc, NULL);
    else
        PyErr_Print();
    
    return 1;
}

我的Python模块由2个文件组成^{

Spam.py

class Spam:
    def __init__(self):
        pass
    def print_stuff(self):
        print((1,2,3))

__init__.py

import Spam as Spam

当我运行C++代码时,我得到以下错误:^ {< CD9>}

我已经尝试将从PyModule_GetDict(pModule)返回的字典内容作为字符串,并确认它没有提到函数

我在文档中查找了PyModule_GetDict,这表示它返回的字典与您在Python中调用模块__dict__时得到的字典相同。当我尝试在__init__.py内部调用Spam.__dict__时,我得到了相同的结果,我的函数丢失了,但当我尝试Spam.Spam.__dict__时,我得到了一个包含该函数的字典

因此,我决定将import语句更改为from Spam import Spam,以便Spam.__dict__现在将包含我的函数,它确实包含了这个函数。但是,运行C++代码时,没有什么变化。我仍然从字典中得到相同的错误,仍然无法调用我的函数

我确实想知道,在我的C++代码中,是否有一个类没有实例,所以我也尝试删除了周围类,并且^ ^ }只包含函数定义,然后导入,但是,同样,我也得到了同样的错误。p>

我有一种预感,这是某种名称空间问题,否则我看不出PyModule_GetDict__dict__如何为同一个模块返回不同的字典,但老实说,我不知道从这里可以走到哪里

是不是我的类^ {CD2>}不被认为是我试图从C++导入的模块的一部分?我的^ { CD5}}缺少什么,或者可能需要在C++中包含另一个语句,以便在导入模块之后导入类,或者在第一个地方没有正确导入模块?p>

我以前见过类似的问题,但它们往往出现在出现异常、搜索路径不正确或先决条件值返回NULL的情况下。我对C++有相当丰富的经验,但对于Python和Python/C API来说,我是新手,虽然我已经阅读了涵盖API基本知识的文档,以及Python中模块是如何工作的。p>


Tags: 模块path函数py字典spamnulldict
1条回答
网友
1楼 · 发布于 2024-09-27 20:18:48

首先,我认为您不需要spam.py中的最后两行。我把它简化为:

class Spam:
    def __init__(self):
        pass
    def print_stuff(self):
        print((1,2,3))

现在,让我们测试模块:

>>> import spam
>>> s = spam.Spam()
>>> s.print_stuff()
(1, 2, 3)

到目前为止,一切顺利。让我们看看我们是否可以从C++中使用它。以下是您的程序的工作版本:

#define PY_SSIZE_T_CLEAN
#include <Python.h>

#include <stdlib.h>

int main()
{
    Py_Initialize();

    //modify python module search path
    auto modulePath = ".";
    PyObject* sysPath = PySys_GetObject("path");
    PyList_Append(sysPath, PyUnicode_FromString(modulePath));

    PyObject* pModule = PyImport_ImportModule("spam");

    PyObject* spam_class = PyObject_GetAttrString(pModule, "Spam");
    if( !spam_class ) { PyErr_Print(); return EXIT_FAILURE; }

    PyObject* spam = PyObject_CallObject(spam_class, NULL);
    if( !spam ) { PyErr_Print(); return EXIT_FAILURE; }
    
    PyObject* pFunc = PyObject_GetAttrString(spam, "print_stuff");

    if (pFunc != NULL)
        PyObject_CallObject(pFunc, NULL);
    else
        PyErr_Print();
    
    return 1;
}

我将模块命名为spam.py,小写。模块对象有一个Spam作为属性。我们得到该类并调用它来创建一个对象,就像我们在Python中所做的那样:

>>> s = spam.Spam()

现在我们有了一个对象。它有一些方法,这些方法是属性,我们可以像往常一样通过PyObject_GetAttrString获得它们。其余的你都知道

我已经有几年没有使用过这种东西了,我的经验来自另一个方面,让Python可以访问C模块。我通过在Python解释器中使用dir来实现上述示例,直到得到所需的内容。如果你“像翻译一样思考”,你可能会发现这一切更有意义

相关问题 更多 >

    热门问题