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

为什么在C+;中导入Python函数的模块后无法访问它+;?,python,c++,python-3.x,python-c-api,Python,C++,Python 3.x,Python C Api,我试图调用一个函数print\u stuff,该函数是C中用户定义的Python模块Spam中类Spam的成员++ #define PY_SSIZE_T_CLEAN #include <Python.h> int main() { Py_Initialize(); //modify python module search path auto modulePath = /* hardcoded search path for module */ P

我试图调用一个函数
print\u stuff
,该函数是C中用户定义的Python模块
Spam
中类
Spam
的成员++

#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;
}
\uuuu init\uuuuu.py

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

当我运行C++代码时,我会得到以下错误:<代码> AtditError:'DICT '对象没有属性“PrrtTyStudio”< /Calp> < /P> 我尝试将从

PyModule_GetDict(pModule)
返回的字典内容作为字符串,并确认它没有提到函数

我在文档中查找了
PyModule\u GetDict
,它返回的字典与在Python中调用模块时得到的字典相同。当我尝试调用
Spam.\uuuuu dict\uuuuu
内部的
\uuu init\uuuuuu.py
时,我得到了相同的结果,我的函数丢失了,但当我尝试
Spam.Spam.\uuuu dict\uuuu
时,我得到了一个包含该函数的字典

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

我确实想知道,在我的C++代码中,是否有一个类没有实例,所以我也尝试删除了周围类,并拥有<代码>垃圾邮件。Py <代码>只包含函数定义,然后导入,但是,同样,我也得到了同样的错误。 我有一种预感,这是某种名称空间问题,否则我不知道

PyModule\u GetDict
\u dict\u\u
如何为同一个模块返回不同的字典,但老实说,我不知道从这里可以走到哪里

是我的类<代码>垃圾邮件<代码>不被认为是我试图从C++导入的模块的一部分吗?是我的C++代码> Pys<代码>缺少什么,或者我需要在C++中包含另一个语句,在导入模块后导入类,或者我没有正确导入模块?


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

< P>首先,我不认为你需要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;
}
现在我们有了一个对象。它有一些方法,这些方法是属性,我们可以像往常一样通过
PyObject\u GetAttrString
获得这些属性。其余的你都知道


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

谢谢,这解决了问题,但我有几个问题。首先,我可能遗漏了一些东西,但您的spam.py版本似乎与我的版本相同,您的意思是init.py是不必要的吗?。其次,我的问题似乎是试图从模块字典中获取函数,而不是从模块中获取类,然后从类中获取函数。我认为类的成员函数对包含的模块实际上是不可见的,这是正确的吗?是的,afaik init.py是不必要的。至于“看不见”,不完全是。记住,Python对象在解释器执行类之前是不存在的。在那之前,它们只是一页纸上的文字。类定义是无生命的;它定义了实例能够做什么,但实例方法不属于该类。这听起来很奇怪,但是您首先执行类来创建一个实例。然后可以调用实例方法。
>>> s = spam.Spam()