为什么我在 C++ 中导入模块后无法访问我的 Python 函数?
Why am I unable to access my Python function after importing its module in C++?
我正在尝试从用户定义的 Python 模块 Spam
中调用函数 print_stuff
,它是 class Spam
的成员C++
#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
和 __init__.py
都位于同一目录 /Spam
中,该目录是包含我的 VS 解决方案和 C++ 代码的目录的子文件夹。
Spam.py
class Spam:
def __init__(self):
pass
def print_stuff(self):
print((1,2,3))
__init__.py
import Spam as Spam
当我 运行 我的 C++ 代码时,出现以下错误:AttributeError: 'dict' object has no attribute 'print_stuff'
我已经尝试从 PyModule_GetDict(pModule)
中获取字典 returned 的内容作为字符串,并确认它没有提到函数。
我查找了 PyModule_GetDict
的文档,其中说它 return 与您在 Python 中的模块上调用 __dict__
的字典相同。当我尝试在 __init__.py
中调用 Spam.__dict__
时,我得到了相同的结果,我的函数丢失了,但是当我尝试 Spam.Spam.__dict__
时,我得到了一个包含该函数的字典。
据此我决定将导入语句更改为 from Spam import Spam
以便 Spam.__dict__
现在可以包含我的函数,它确实这样做了。但是,当我 运行 我的 C++ 代码时,没有任何变化。我仍然从我的字典中得到同样的错误并且仍然无法调用我的函数。
我确实想知道这是否是我的 C++ 代码中没有 class 实例的问题,所以我也尝试删除周围的 class 并拥有 Spam.py
只包含函数定义,然后导入它,但是,我又遇到了同样的错误。
我有预感这是某种命名空间问题,否则我不明白 PyModule_GetDict
和 __dict__
怎么可能 return 同一模块的不同字典,但老实说我不知道从这里去哪里。
我的 class Spam
不被认为是我试图从 C++ 导入的模块的一部分吗?我的 __init__.py
是否遗漏了一些东西,或者我可能需要在 C++ 中包含另一条语句以在导入模块后导入 class 还是我一开始没有正确导入模块?
我以前见过类似的问题,但它们往往出现在引发异常、搜索路径不正确或先决条件值 return 为 NULL 的情况下。我对 C++ 相当有经验,但对 Python 是新手,对 Python/C API 还是新手,尽管我已经阅读了涵盖 API 基础知识以及如何使用模块的文档在 Python.
工作
首先,我认为您不需要 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
class 作为属性。我们得到 class 并 调用它 来创建一个对象,就像我们在 Python:
中所做的那样
>>> s = spam.Spam()
现在我们有了对象。它有方法,这些方法是属性,我们可以像往常一样用 PyObject_GetAttrString
获得。剩下的你就知道了。
我已经有几年没有接触过这些东西了,我的经验来自另一面,让 Python 可以访问 C 模块。我通过在 Python 解释器中使用 dir
来完成上面的示例,直到我得到我需要的东西。如果您“像口译员一样思考”,您可能会发现这一切都更有意义。
我正在尝试从用户定义的 Python 模块 Spam
中调用函数 print_stuff
,它是 class Spam
的成员C++
#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
和 __init__.py
都位于同一目录 /Spam
中,该目录是包含我的 VS 解决方案和 C++ 代码的目录的子文件夹。
Spam.py
class Spam:
def __init__(self):
pass
def print_stuff(self):
print((1,2,3))
__init__.py
import Spam as Spam
当我 运行 我的 C++ 代码时,出现以下错误:AttributeError: 'dict' object has no attribute 'print_stuff'
我已经尝试从 PyModule_GetDict(pModule)
中获取字典 returned 的内容作为字符串,并确认它没有提到函数。
我查找了 PyModule_GetDict
的文档,其中说它 return 与您在 Python 中的模块上调用 __dict__
的字典相同。当我尝试在 __init__.py
中调用 Spam.__dict__
时,我得到了相同的结果,我的函数丢失了,但是当我尝试 Spam.Spam.__dict__
时,我得到了一个包含该函数的字典。
据此我决定将导入语句更改为 from Spam import Spam
以便 Spam.__dict__
现在可以包含我的函数,它确实这样做了。但是,当我 运行 我的 C++ 代码时,没有任何变化。我仍然从我的字典中得到同样的错误并且仍然无法调用我的函数。
我确实想知道这是否是我的 C++ 代码中没有 class 实例的问题,所以我也尝试删除周围的 class 并拥有 Spam.py
只包含函数定义,然后导入它,但是,我又遇到了同样的错误。
我有预感这是某种命名空间问题,否则我不明白 PyModule_GetDict
和 __dict__
怎么可能 return 同一模块的不同字典,但老实说我不知道从这里去哪里。
我的 class Spam
不被认为是我试图从 C++ 导入的模块的一部分吗?我的 __init__.py
是否遗漏了一些东西,或者我可能需要在 C++ 中包含另一条语句以在导入模块后导入 class 还是我一开始没有正确导入模块?
我以前见过类似的问题,但它们往往出现在引发异常、搜索路径不正确或先决条件值 return 为 NULL 的情况下。我对 C++ 相当有经验,但对 Python 是新手,对 Python/C API 还是新手,尽管我已经阅读了涵盖 API 基础知识以及如何使用模块的文档在 Python.
工作首先,我认为您不需要 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
class 作为属性。我们得到 class 并 调用它 来创建一个对象,就像我们在 Python:
>>> s = spam.Spam()
现在我们有了对象。它有方法,这些方法是属性,我们可以像往常一样用 PyObject_GetAttrString
获得。剩下的你就知道了。
我已经有几年没有接触过这些东西了,我的经验来自另一面,让 Python 可以访问 C 模块。我通过在 Python 解释器中使用 dir
来完成上面的示例,直到我得到我需要的东西。如果您“像口译员一样思考”,您可能会发现这一切都更有意义。