Python时现在很火的一种语言,在云计算、人工智能、自动化测试等领域使用率非常高。之所以有这么大的市场使用率,python也是有它自己的独特之处,首先python易学,并且是一种解释性语言,不需要经过编译,并且它有着非常丰富的第三方库,可以帮助你处理各种工作,包括:电子邮件、数据库、web、GUI、单元测试等。Python采用强制缩进的方式使得代码有着极佳的可读性。
但python也有自己的缺点:就是运行速度,如果有速度要求的话,建议用c或c++改写关键部分,可以提高运行速度。
这样就会牵涉到混合编程的模式,即python如何调用使用c或c++实现的接口。
本文的主要目的就是介绍python与c/c++如何实现混合编程。
环境:
Python3.5 vim ctypes swig3.0.8 centos
python 可以通过使用 ctypes 模块调用 c 函数,这其中必定包括可以定义 c 的变量类型(包括结构体类型、指针类型)。
官方给的定义是 “ctypes is a foreign function library for Python. It provides C compatible data types, and allows calling functions in DLLs or shared libraries. It can be used to wrap these libraries in pure Python.” —— 引自 Python 3.5 chm 文档。其大意就是——ctypes 是一个为 Python 准备的外部函数库。它提供兼容C的数据类型,并允许调用DLL或共享库中的函数。通过它,可以使用纯粹的 Python 包装这些函数库(这样你就可以直接 import xxx 来使用这些函数库了)。
具体实例可以参考:
https://github.com/zhaohb/python-call-C-API lib目录
python时如何通过ctype调用c的接口:
首先需要加载由c代码编译生成的动态库,得到代表动态库的对象,然后通过该对象调用库中的接口,具体代码:
通过上述代码可以看到具体ctype的用法,python中定义的plus接口就是通过调用c语言实现的plus接口实现的。
c类型与Python类型:参数类型、返回类型:
C语言的类型与python的数据类型时不一样的,但是ctypes可以实现C语言类型与python类型的透明转换。
在上述实例中其实有一个取巧的地方:就是利用了python默认函数的参数类型和返回类型都是int型,而C语言中plus接口的参数和返回值类型也都是int型,这样就不用显示的告诉python这个lib库中的函数的参数和返回值类型,如果C语言中plus的参数和返回值类型时float类型,这时候就需要显示的指定,通过函数的两个属性restype和argtypes赋值了:
lib.plus.argtypes = (c_float, c_float) # plus 有两个形参,都是 float 类型
lib.plus.restype = c_float # plus 返回值的类型是 flaot
然后再按之前的方式调用:
lib.plus.(1,2)
这里还有一个特殊情况,就是返回值或者参数时结构体的情况,在python中是没有结构体的概念的,但是为了能在python中表示一个结构体,我们可以在python中定义一个类,用来表示C语言中的结构体类型:
该图中展示的时C语言中对StructTest结构体的定义:
该图中展示的是在python中如何表示StructTest结构体,两个要点:
1.类必须继承自ctypes.Structure
2.描述结构体成员时需要在类中顶一个一个_fields_的属性,并赋值给表示成员的一个列表。
这样就可以正常使用StructTest结构体了:
指针类型:
主要有三个与指针相关的ctypes函数:
pointer 和 POINTER 的区别是,pointer 返回一个实例,POINTER 返回一个类型具体的使用可以参考setinfo接口。
Swig是另外一种把c/c+代码家口给python或其他语言调用的工具,SWIG本质上是个代码生成器,为C/C++程序生成到其他语言的包装代码(wrapper code),这些包装代码里会利用各语言提供的C API,将C/C++程序中的内容暴露给相应语言。为了生成这些包装代码,SWIG需要一个接口描述文件,描述将什么样的接口暴露给其他语言。SWIG的 接口描述文件可以包含以下内容:1)ANSI C函数原型声明 2)ANSI C变量声明 3) SWIG指示器(directive)相关内容。SWIG可以直接接受”.h”头文件做为接口描述文件。在有了接口描述文件后,就可以利用swig命令生 成包装代码了,然后将包装代码编译链接成可被其他语言调用的库。
SWIG包含以下几部分内容:
1.一个代码生成器(swig):代码生成器根据接口说明文件,生成相应的包装代码。
2.一个库:SWIG将常用的内容放到SWIG库里了,比如对数组、指针的支持,字符串支持,STL支持等。可以在接口文件中直接引用库里的内容,大大方便接口文件的编写。
具体实例可以参考:
https://github.com/zhaohb/python-call-C-API swig目录
swig通过解析C头文件并自动创建扩展代码来操作,要使用swig首先需要一个c有文件,有了头文件下一步就是编写一个swig的接口文件,按照约定,这些文件以“*.i”作为后缀一旦写好了接口文件,就可以在命令行中调用swig了:
通过上述三条命令会在当前目录下生成一个so文件,该文件可以被python直接引用,就可以直接使用里面的接口了。
ctypes不需要程序员熟悉C/C++语言,不需要安装一个C/C++的编译器,它通过操作系统的接口直接操作C/C++代码。而且ctypes是标准库的一部分,只要安装了Python就可以直接使用。这几个原因使得它深受Python程序员的喜爱;而它的劣势就是对c++支持不好。
使用SWIG,通过编写一个接口文件,使用类似于C/C++语法——声明函数、类型的信息,然后使用特殊的工具为C/C++的代码生成Python的接口代码。这些接口代码能够在Python与C/C++之间的数据结构转换。最终编译这些接口代码,成为Python的二进制模块。SWIG的接口文件与C/C++的头文件非常相似。SWIG能够为多种脚本语言生成转换代码。