Python 3.8:运行外部 C++ 代码:无法导入模块

Posted

技术标签:

【中文标题】Python 3.8:运行外部 C++ 代码:无法导入模块【英文标题】:Python 3.8: Running External C++ Code: Unable to Import Module 【发布时间】:2020-06-11 11:29:54 【问题描述】:

我正在构建一个 C++ DLL 文件,我试图将其加载到 Python 模块中。 我正在使用the official Python Documentation。 C++ 代码(包括所有样板)如下(一个酒窝“hello”函数):

#include <Python.h>

#include <iostream>

PyObject* fft_hello(PyObject *self, PyObject *args)
  std::cout << "Insid fft hello" << std::endl;
  return nullptr;


static PyMethodDef fft_methods[2] = 
    "hello", fft_hello, METH_VARARGS, "Runs hello",
    nullptr, nullptr, 0, nullptr
;

static struct PyModuleDef fft_module = 
    PyModuleDef_HEAD_INIT,
    "fft",
    "fft module",
    0,
    fft_methods
;

PyMODINIT_FUNC
PyInit_fft(void)
  std::cout << "INITING" << std::endl;
  return PyModule_Create(&fft_module);

编译模块的CMAKE是:

cmake_minimum_required(VERSION 3.16)
project(fft)

set(CMAKE_CXX_STANDARD 14)
link_directories("C:/Users/guyy/AppData/Local/Programs/Python/Python38/libs")

add_library(fft SHARED fft.cpp )

include_directories("C:/Users/guyy/AppData/Local/Programs/Python/Python38/include")

这会产生一个fft.dll 模块。

接下来,我把这个dll放在python文件目录下并尝试导入:

import fft

if __name__ == '__main__':
    pass

我收到了ModuleNotFoundError: No module named 'fft' 错误。

那么,我做错了什么?

C++ 文件是否写错了? DLL 模块是否构建错误? DLL 模块是否放错了位置?

【问题讨论】:

我建议使用 Cython 而不是自己编写本机模块。 【参考方案1】:

检查:https://docs.python.org/2/library/ctypes.html 或 CPython。

[已编辑] 您也可以使用 distutils。在根文件夹创建一个名为 setup.py 的文件,其实现如下:

从 distutils.core 导入设置,扩展

def main():
    setup(name="fft",
          version="1.0.0",
          description="Python interface for the fft C library function",
          author="<your name>",
          author_email="your_email@gmail.com",
          ext_modules=[Extension("fft", ["fft.cpp"])])

if __name__ == "__main__":
    main()

运行以下命令:

python setup.py install

基本上,这将创建一个名为 fft%python_version_and_distribution%.pyc 的模块,您可以将其添加到文件夹的根目录。这个模块现在可以被你的 python 文件读取。 您也可以在此模块上运行 cmake,但它有点复杂。 我建议查看 distutils 库以获取更多详细信息。

希望对你有帮助

【讨论】:

不幸的是,创建 lib 文件不起作用。我仍然收到与ModuleNotFoundError 相同的错误。我会尝试使用CTYPES,但这看起来有点矫枉过正,尤其是因为我使用的是 C++ 而不是 C。【参考方案2】:

您是否绝对需要将 DLL 作为“模块”加载?

使用 CTYPES 并不复杂。我将它与 Python 3.8 和一个使用 VC++2010 生成的 DLL 一起使用(这个 DLL 实现了多线程代码并且运行良好)。

在 C/C++ 代码方面: - 为所有可调用函数添加前缀'extern "C"',最好使用标准类型的变量和指针,例如:

extern "C" int myTestFunc(int par1, int par2, float *array1)

  ...
  return 0;

在 Python 代码方面: -导入以下模块: 导入 ctypes 导入_ctypes

-在您的代码/类中,将 DLL 加载为:

self.lib = ctypes.CDLL('<full_path_to_your_DLL>')

-声明你的函数的返回类型(函数名必须与C代码中的相同):

self.lib.myTestFunc.restype = ctypes.c_int

- 定义函数参数类型(以下是标准值参数以及指向 numpy 浮点数组的指针):

self.lib.myTestFunc.argtypes = [ctypes.c_int, ctypes.c_int, np.ctypeslib.ndpointer(dtype=np.float32)]

-在您的代码中,只需调用函数:

val1 = 1
val2 = 2
float_array = np.zeros((20, 50),dtype=np.float32)
retval = self.lib.myTestFunc(val1,val2,float_array)

-如果需要释放DLL访问,可以使用如下:

_ctypes.dlclose(self.lib._handle)

【讨论】:

以上是关于Python 3.8:运行外部 C++ 代码:无法导入模块的主要内容,如果未能解决你的问题,请参考以下文章

为啥我不能在 Python 3.8 中使用 pip? [复制]

c++中调用python脚本提示 error LNK2001: 无法解析的外部符号 __imp_Py_Initialize等错误的解决方法

如何在 Windows 上安装 pyodbc 以与 Python 3.8 一起使用?

无法从子进程访问内存映射(Python 3.8)

无法在 Python 上安装模块

无法在 python 3.8 中访问嵌套的 JSON