在 C++ 程序中调用 Cython (Python3.6)

Posted

技术标签:

【中文标题】在 C++ 程序中调用 Cython (Python3.6)【英文标题】:Call Cython (Python3.6) in C++ Program 【发布时间】:2018-07-12 17:36:39 【问题描述】:

我正在做一个项目,我需要在 C++ 中嵌入一些 python 代码。我一直在尝试 Cython 一段时间,但我仍然有很多问题。这是我尝试过的演示。

这里有几个包含结构和函数的文件:

首先,这是文件cat.pyx

cdef public struct Cat:
    int num

cdef public setCatNum(Cat* cat):
    cat.num = 100

cdef public int getCatNum(Cat* cat):
    return cat.num

及其.pxd 文件cat.pxd

cdef public struct Cat:
    int num

cdef public setCatNum(Cat* )
cdef public int getCatNum(Cat* )

这是我的setup.py

from distutils.extension import Extension
from Cython.Distutils import build_ext

ext_modules = [
    Extension("cat", ["cat.pyx"], include_dirs=['.']),
    ]

setup(
  name='dotest',
  cmdclass='build_ext': build_ext,
  ext_modules=ext_modules,
  script_args=['build_ext'],
  options='build_ext':'inplace':True, 'force':True
)

它可以正确编译,但是在生成的cat.h 文件中,函数声明是别的东西:

__PYX_EXTERN_C PyObject *__pyx_f_3cat_setCatNum(struct Cat *); __PYX_EXTERN_C int __pyx_f_3cat_getCatNum(struct Cat *);

那么我如何在我的 C/C++ 程序中调用这些函数呢?提前谢谢你。

【问题讨论】:

你读过this documentation?我假设你有,因为你正确地制作了函数public。我认为它应该生成更简单的名称... 是的,我确实阅读了那个例子。它说在 python 3.x 中我应该导入一个模块。但是我不太明白如何使用该模块来调用文档中的那些函数。 【参考方案1】:

我不确定为什么它会为公共函数生成混乱的名称 - 它与 the documentation 背道而驰。然而,它也为我做。我怀疑这是一个错误,但目前建议您只使用损坏的名称。

您可能希望将setCatNum 的返回类型设置为void。目前它返回一个没有用的PyObject*(总是None),这意味着你必须处理它的引用计数。

cdef public void setCatNum(Cat* )

我认为您感到困惑的是 Python 2 和 3 之间的区别。文档建议将 init<modulename> 替换为

err = PyImport_AppendInittab("modulename", PyInit_modulename);
Py_Initialize();
modulename_module = PyImport_ImportModule("modulename");

这是您需要进行的唯一更改 - 您实际上不需要使用模块对象。

一个工作示例:

#include <Python.h>
#include "cat.h"
#include <iostream>

int main() 

    auto err = PyImport_AppendInittab("cat", PyInit_cat);
    if (err) 
        std::cout << "ERROR!\n";
        return 1;

    
    Py_Initialize();
    auto cat_module = PyImport_ImportModule("cat"); // you don't actually have to do anything with this module object
    Cat c;
    __pyx_f_3cat_setCatNum(&c);
    std::cout << __pyx_f_3cat_getCatNum(&c) << "\n";
    Py_Finalize();

使用

在 Linux 上成功编译
g++ example_cpp.cpp -o example `python3-config --includes --libs` ./cat.cpython-36m-x86_64-linux-gnu.so

(您可能需要更改确切的 cat 文件名)

【讨论】:

非常感谢。它现在也为我工作。但是有没有其他方法可以避免这些名称损坏? @hiimdaosui 这很奇怪,但是当我使用“cython cat.pyx”构建时,我得到的函数名称不会被修改... @ead 当我尝试cython cat.pyx 时,它仍然给了我错位的功能...... 我认为这可能是某些 Cython 版本中引入的错误。我会确保 Cython 更新到最新版本,如果不能解决它,请在 github 上提交错误报告 我会尝试删除(或修复?)cat.pxd【参考方案2】:

正常的 cython 开发模式完全相反——你可以使用它从 python 调用 C++ 代码,而不是。

对 cython 常见用法的简单描述是“用类似 python 的高级语言编写代码,然后将其转换为用于 python 扩展的 C 源代码”

生成的 C 代码不可读,不打算从 C 中使用。

tl;dr 使用 cython 使您的 C/C++ 程序可从 python 调用,并编写 python 代码来调用它。

【讨论】:

到目前为止,这不是我从其他资源中发现的。喜欢***.com/questions/22589868/…。但我认为这只是我的代码不起作用,可能有解决方案。 @hiimdaosui 我从来没有说过不可能,只是不正常——就像逆潮流而行 @hiimdaosui 这是一本不错的读物twistedmatrix.com/users/glyph/rant/extendit.html 好的,我明白你在说什么。但是在我的项目中,我已经有很多用 python 编码的功能,它们严重依赖于一些第三方库,如 opencv 和 tensorflow。但最终我需要使用 C++ 程序来调用这些函数。所以我在这里很困惑。我必须用 C++ 重写所有这些代码吗? @hiimdaosui “但是我需要使用 C++ 程序来调用这些函数” 为什么?那很可能是假的!是什么迫使您从 C++ 调用它们?难道你不能只使用 python 并从 python 调用 C++ 部分吗?

以上是关于在 C++ 程序中调用 Cython (Python3.6)的主要内容,如果未能解决你的问题,请参考以下文章

将 3D numpy 数组从 cython 传递到 C++

带有类方法的 Cython 回调

Cython 中 C++ 函数的性能不佳

如何在 Cython 中使用不同的 C++ 编译器?

如何使用 cython 将 python 类公开给 c++

从 cython c 调用 python 函数时的奇怪行为