📜  如何从Python调用 CC++?(1)

📅  最后修改于: 2023-12-03 15:23:47.573000             🧑  作者: Mango

如何从Python调用 C/C++?

简介

Python是一门高级编程语言,在编写时不需要关心内存管理和二进制代码生成等底层问题,这可以让开发者更加专注于业务逻辑。然而,Python在处理高性能、低延迟和大数据操作等方面存在一些限制,因此有时我们需要使用C/C++等底层语言来实现更高效的算法和计算。

在本篇文章中,我们将介绍如何从Python中调用C/C++代码,以便在Python中获取其优势。

ctypes库

Python提供了ctypes库作为C语言库调用的接口。ctypes可以用来编写纯Python代码来访问C API中的函数和全局变量,而无需编写任何C代码。ctypes支持多种操作系统和C语言根据ABI的编译方式。

声明函数和类型

在使用ctypes时,我们需要根据C语言的数据类型和函数声明来定义其Python的类型。例如,下面是一个C语言中的函数:

int add(int a, int b);

在Python中我们需要将其转化为ctypes可接受的类型声明:

from ctypes import c_int, cdll

# 声明函数参数和返回值类型
add = cdll.LoadLibrary("./libadd.so").add
add.argtypes = (c_int, c_int)
add.restype = c_int

# 调用函数
result = add(1, 2)
print(result) # 3

在上面的代码中,我们通过使用cdll模块的LoadLibrary方法加载动态库,并定义函数的签名。argtypes用于定义函数的参数类型,如果函数不需要参数,我们可以忽略这个属性。restype用于定义函数的返回值类型。

调用动态库

要从Python中调用C/C++动态库,我们可以使用cdll库。下面是一个简单的例子:

# 加载动态库
lib = cdll.LoadLibrary('./libsample.so')

# 调用其中的test()函数
lib.test()
Ctypes与Numpy

numpy是科学计算中必备的库之一,因此,ctypes库也支持与Numpy库的无缝集成。例如,在使用ctypes调用C语言的库时,我们可以使用numpy来传递多维数组。

from ctypes import *

import numpy as np

# 声明函数参数和返回值类型
f = cdll.LoadLibrary('libsample.so').f
f.restype = c_void_p
f.argtypes = [c_int, POINTER(c_double)]

# 构造测试数组
x = np.array([0, 1, 2, 3], dtype=float64)

# 调用函数
res = f(len(x), x.ctypes.data_as(POINTER(c_double)))

在上面的代码中,我们使用ctypes和numpy来传递多维数组,其中ctypes使用POINTER(c_double)表示一个C语言中的double类型,而我们在Python中使用numpy的float64类型。

Cython

另一种将Python集成C/C++代码的方式是使用Cython。Cython是用Python编写的编译器,它可以将Python代码转换为C代码,并可以作为Python模块导入到运行时环境中。

与ctypes不同,Cython可以在静态类型语言C/C++的帮助下实现更高效的代码执行,同时不损失Python的易用性和可读性。

使用Cython的基本流程:

  1. 将Python代码转换为Cython文件。
  2. 编译生成Python模块。

下面是一个简单的Python函数:

def add(a, b):
    return a + b

下面是使用Cython优化后的代码:

# 引入Cython装饰器
%load_ext cython

# 定义Cython版本
%%cython
cpdef int add(int a, int b):
    return a + b

可以看到,在使用Cython后,我们的函数中多了一个cpdef关键字。cpdef将Python函数声明为既能在Python中使用的Python函数,也能在Cython转换为C的代码中使用的C函数。

编译Cython代码

Cython支持多种编译选项。其中,cythonize选项可以将Cython代码转换为C代码并构建成扩展模块。

例如,我们可以使用以下命令将Cython代码转换为C代码:

cython --embed -3 file.pyx

这里,使用--embed选项可以将Cython代码与Python解释器静态链接,从而将其打包成一个可执行文件,而-3选项则将Cython代码生成对应的Python 3代码。

接下来,编译生成Python模块:

gcc -Os -I /usr/include/python3.6/ -o file file.c -lpython3.6m

在上面的过程中,我们使用gcc编译器编译了生成的C代码,并将其链接到Python解释器上。

导入并调用Cython代码

完成Cython的编译后,我们就可以在Python中导入其生成的模块了。例如,在上面的代码中,我们生成了一个名为file的可执行文件。我们可以在Python中这样使用它:

import file

# 调用Cython的函数
result = file.add(1, 2)
print(result) # 3
总结

在本文中,我们介绍了如何从Python中调用C/C++代码。我们使用了Python的内置ctypes库和Cython编译器。我们还介绍了如何使用ctypes和Cython集成Numpy等常见Python库。

对于需要高性能计算的任务,我们可以使用C/C++等底层语言来实现更高效算法和计算,同时Python的易用性也允许我们将Python与底层语言的优势相结合。