You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C++中调用经Cython编译为C的Python函数?

问题

通常开发者会用C扩展Python,但我需要相反的场景:在C++项目中使用Python代码。

我已通过Cython将简单的.pyx文件转换为C文件,函数仅包含打印逻辑,代码如下:

# hello_cython.pyx
def func1():
    print("Hello Cython Function.")

if __name__ == "__main__":
    print("Hello World! Run cython.")

参考用的setup.py代码:

# setup.py
from setuptools import setup, Extension
from Cython.Build import cythonize

setup(
    name="AppHi",
    ext_modules=cythonize("hello_cython.pyx", show_all_warnings=True),  
)

执行python setup.py build_ext --inplace生成C文件后,我将其加入C项目,已修复缺失的头文件和库依赖,编译无报错,但C的main函数中无法调用原Python定义的func1:

// LearnPythonAPIIntegration.cpp : This file contains the 'main' function. Program execution begins and ends there.
//

#include <iostream>

int main()
{
    std::cout << "Hello World!\n";
    /// 想在这里调用func1()
}

不清楚是否操作有误,或是无法复用该代码只能用C++重写,请问如何解决?

解决方案

1. 修改Cython代码暴露C可调用接口

默认Cython生成的函数仅作为Python模块内部接口,无法直接被C/C++调用,需要显式声明C兼容的接口。修改hello_cython.pyx:

# hello_cython.pyx
cdef public void func1_c():
    print("Hello Cython Function.")

def func1():
    func1_c()

if __name__ == "__main__":
    print("Hello World! Run cython.")

这里用cdef public声明一个C可见的函数func1_c,原Python函数func1可保留供Python调用,同时C/C++能直接调用func1_c。

2. 重新生成编译文件

执行原命令重新生成C文件和对应头文件:

python setup.py build_ext --inplace

生成的文件中会包含hello_cython.h,里面有func1_c的函数原型声明。

3. 在C++项目中调用函数

3.1 引入头文件

在C++代码中添加必要的头文件:

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

3.2 初始化Python运行时并调用函数

由于Cython生成的代码依赖Python解释器,必须先初始化再调用函数:

int main()
{
    std::cout << "Hello World!\n";

    // 初始化Python解释器
    Py_Initialize();

    // 导入生成的模块(必须执行,否则函数无法正常工作)
    PyImport_ImportModule("hello_cython");

    // 调用Cython暴露的C函数
    func1_c();

    // 清理Python解释器
    Py_Finalize();

    return 0;
}

3.3 编译链接配置

确保C++项目的编译配置包含:

  • Python头文件目录(如Linux下/usr/include/python3.x,Windows下Python安装目录的include文件夹)
  • 链接Python库文件(如Linux下python3.x,Windows下python3x.lib)
  • 链接Cython生成的目标文件或库文件(如hello_cython.o或hello_cython.lib)

替代方案:直接通过Python C API调用

如果不想修改Cython代码,也可以直接用Python C API在C++中调用Python模块的函数:

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

int main()
{
    std::cout << "Hello World!\n";

    Py_Initialize();

    // 导入目标模块
    PyObject* module = PyImport_ImportModule("hello_cython");
    if (!module) {
        PyErr_Print();
        return 1;
    }

    // 获取函数对象
    PyObject* func = PyObject_GetAttrString(module, "func1");
    if (!func || !PyCallable_Check(func)) {
        PyErr_Print();
        Py_DECREF(module);
        return 1;
    }

    // 调用无参函数
    PyObject* result = PyObject_CallObject(func, nullptr);
    if (!result) {
        PyErr_Print();
    }

    // 释放Python对象引用
    Py_XDECREF(result);
    Py_DECREF(func);
    Py_DECREF(module);

    Py_Finalize();

    return 0;
}

这种方式无需修改Cython代码,但需要手动管理Python对象的引用计数。


内容的提问来源于stack exchange,提问作者Grzegorz Krug

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 08:32:04