SWIG给C结构增加‘成员函数’
以前一直以为C不支持面向对象,为python写扩展真是太憋屈了,但是今天看了SWIG的文档,原来人家早就解决了这个问题。
由于之前看的是《Python科学计算》上面关于swig的简单介绍,上面说了如何在python中如何像类一样的使用C结构,但是也只是停留在如何使用结构的成员数据上,但是没有讲如何将C的函数封装成python的类方法的方法。相反由于C++有原生OOP的支持,固然swig直接可以将C++的类封装成python的类。所以我以前一直认为这时候只能用C++了。
但其实,还是读书读的少啊。swig这么强大的封装工具,这早就想到了。毕竟OO是一种思想,C照样能写出OO的代码来(多重继承和多态这种行么?)。
所以今天看到swig文档中关于%extend
指令的介绍才感觉相见恨晚啊。
给C结构添加成员函数
C语言的OO通常都是写操作结构的接口函数,尽管SWIG为C++提供了直接的面向对象的类映射,C却没有。尽管如此SWIG还是提供了一个%extend
指令,就是这个指令能够将C语言封装成支持OO的语言的接口。
向已定义的结构添加成员函数
具体的使用方法:
1 | typedef struct Vector { |
这样封装的话在python中只能这样调用:
1 | 1.0, 2.0, 3.0); v = Vector( |
但是这个类并没有成员函数,那如何给这个结构绑定函数,并封装成python类的成员函数呢?上
%extend
!1 | // file : vector.i |
是的,通过上面的代码可以看出SWIG在模仿C++的语法,其中构造函数和析构函数就不多说了。
$self
是一个内置的变量,作用类似于C++中的this
,也就是指向当前对象的指针。
%extend
指令不仅定义了成员函数,而且还相当于在vector.i
文件中对这些函数进行了声明,这样不仅C编译器会编译这些函数,SWIG也会处理这些函数生成接口代码。
这样我们在Python中就可以这样使用:
1 | from vector import * |
在定义结构的时候直接添加成员函数
1 | // file : vector.i |
使用已定义的函数作为结构的成员函数
如果在源代码中的实现文件中已经定义结构的接口函数(名称要按照swig的规定),则可以直接在结构定义中扩展这些函数。
例如如果我在实现文件中定义了如下几个函数
1 | // file : vector.c |
然后我在
*.i
文件中给SWIG声明Vector类的时候就可以直接添加成员函数1 | // file : vector.i |
这里感觉和C++很像了,有了`%extend`的struct就相当于直接在头文件中定义类(包括成员数据和成员函数),然后类成员函数的实现在实现代码中。
但是这里的命名是由要求的,因为在python中或者其他目标语言中调用成员方法是通过调用
Vector_print
来实现的,因此如果要认为定义成员函数,函数的名称也要符合这些规则。