簡體   English   中英

為什么在 C++ 中導入其模塊后,我無法訪問我的 Python function?

[英]Why am I unable to access my Python function after importing its module in C++?

I am attempting to call a function print_stuff which is a member of the class Spam from a user-defined Python module Spam in 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)返回的字典內容作為字符串,並確認它沒有提到 function。

我查找了PyModule_GetDict的文檔,它說它返回的字典與您在 Python 中的模塊上調用__dict__時返回的字典相同。 當我嘗試在__init__.py中調用Spam.__dict__時,我得到了相同的結果,我的 function 丟失了,但是當我嘗試Spam.Spam.__dict__時,我得到了一個包含 function 的字典。

從此,我決定將 import 語句更改為from Spam import Spam ,以便Spam.__dict__現在包含我的 function,它確實做到了。 但是,當我運行 C++ 代碼時,沒有任何變化。 我的字典仍然出現同樣的錯誤,並且仍然無法調用我的 function。

I did wonder if it was an issue of not having an instance of the class in the my C++ code, so I also tried removing the surrounding class and having Spam.py just contain the function definition and then importing that but, again, I got同樣的錯誤。

我有一種預感,這是某種命名空間問題,否則我看不出PyModule_GetDict__dict__如何為同一個模塊返回不同的字典,但老實說,我不知道 go 從這里到哪里。

我的 class Spam是否不被視為我嘗試從 C++ 導入的模塊的一部分? 我的__init__.py是否缺少某些內容,或者我可能需要在 C++ 中包含另一條語句以在我導入模塊后導入 class 還是我首先沒有正確導入模塊?

我以前見過類似的問題,但它們往往出現在引發異常、搜索路徑不正確或先決條件值之一返回 NULL 的情況下。 I am fairly experienced with C++ but am new to Python and newer still to the Python/C API, although I have read the docs covering the basics of the API and how modules work in 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 ,小寫。 模塊 object 具有Spam class作為屬性。 我們得到 class 並調用它來創建 object,就像我們在 Python 中所做的那樣:

>>> s = spam.Spam()

現在我們有一個 object。 它有方法,它們是屬性,我們可以像往常一樣使用PyObject_GetAttrString獲得。 您知道 rest。

自從我使用這些東西已經有幾年了,我的經驗來自另一方面,使 Python 可以訪問 C 模塊。 我通過在 Python 解釋器中使用dir來完成上述示例,直到我得到我需要的東西。 如果您“像口譯員一樣思考”,您可能會發現這一切都更有意義。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM