Cython编程入门

来源:互联网 发布:mac只装win10单系统 编辑:程序博客网 时间:2024/06/10 10:08

本文主要以[Learning Cython Programming]一书中的案列和我自己编写的简单程序来学习Cython。

一:Python调用C函数

mycode.c文件

[python] view plaincopy在CODE上查看代码片派生到我的代码片
  1. #include <stdio.h>  
  2.   
  3. int myfunc (int x, int y)  
  4. {  
  5.   printf ("look we are within your c code!!\n");  
  6.   return x + y;  
  7. }  
mycode.h文件:

[python] view plaincopy在CODE上查看代码片派生到我的代码片
  1. #ifndef __MYCODE_H__  
  2. #define __MYCODE_H__  
  3. extern int myfunc (int, int);  
  4. #endif //__MYCODE_H__  
我们将通过Python调用myfunc函数。

mycodepy.pyx文件:

[python] view plaincopy在CODE上查看代码片派生到我的代码片
  1. cdef extern from "mycode.h":  
  2.     cdef int myfunc (int, int)  
  3.   
  4. def callCfunc ():  
  5.     print myfunc (1,2)  

cdef是Cython的关键字,说明要引用外部的声明。我们创建一个callCfunc函数是有必要的,这是对C中函数的包装,Cython会处理好Python和C之间的类型转换。

注意当cdef开始一个块的时候,下面所有的类型默认都已添加cdef关键字。我们还可以传递参数给callCFunc,下面是我修改后的mycodepy.pyx文件:

[python] view plaincopy在CODE上查看代码片派生到我的代码片
  1. cdef extern from "mycode.h":  
  2.     int myfunc (int, int)  
  3.   
  4. def callCfunc ():  
  5.     print myfunc (1,2)  
  6.   
  7. def f(a,b):  
  8.     print a,b  
  9.     print myfunc(a,b)  

这里还有一点,在定义f时可使用C语言的关键字,如def f(int a,int b),Cython将会优化代码,减少类型转换,增加效率。即使同样的算法,使用C的关键字将带来质的飞跃。

Makefile文件如下:

[python] view plaincopy在CODE上查看代码片派生到我的代码片
  1. all:  
  2.     cython mycodepy.pyx  
  3.     gcc -g -O2 -fpic -c mycodepy.c -o mycodepy.o `python-config --includes`  
  4.     gcc -g -O2 -fpic -c mycode.c -o mycode.o  
  5.     gcc -g -O2 -shared -o mycodepy.so mycodepy.o mycode.o `python-config --libs`  
  6.   
  7. clean:  
  8.     rm -f mycodepy.c *.o *.so  

这里需要提示一下,‘python-config'是编译python时提供的一个命令行工具,目的是更容易的找到Python的头文件和库文件位置。

如在我系统中,

python-config --includes: -I/usr/local/include/python2.6

pyhton-config --libs:  -lpthread -ldl -lutil -lm -lpython2.6

运行结果:


二:Python中使用C的结构体

mycode.h文件:

[python] view plaincopy在CODE上查看代码片派生到我的代码片
  1. #ifndef __MYCODE_H__  
  2. #define __MYCODE_H__  
  3.   
  4. struct mystruct {  
  5.   char * string;  
  6.   int integer;  
  7.   char ** string_array;  
  8. };  
  9.   
  10. extern void printStruct (struct mystruct *);  
  11.   
  12. #endif //__MYCODE_H__  
mycode.c文件:

[python] view plaincopy在CODE上查看代码片派生到我的代码片
  1. #include <stdio.h>  
  2. #include "mycode.h"  
  3.   
  4. void printStruct (struct mystruct * s)  
  5. {  
  6.   printf (".string = %s\n", s->string);  
  7.   printf (".integer = %i\n", s->integer);  
  8.   printf (".string_array = \n");  
  9.   
  10.   int i;  
  11.   for (i = 0; i < s->integer; ++i)   
  12.     printf ("\t[%i] = %s\n", i, s->string_array [i]);  
  13. }  
我们将通过Python调用printStruct函数:

mycodepy.pyx:

[python] view plaincopy在CODE上查看代码片派生到我的代码片
  1. cdef extern from "mycode.h":  
  2.   struct mystruct:  
  3.     char * string  
  4.     int integer  
  5.     char ** string_array  
  6.   void printStruct (mystruct *)  
  7.   
  8. def testStruct ():  
  9.     cdef mystruct s  
  10.     cdef char *array [2]  
  11.     s.string = "Hello World"  
  12.     s.integer = 2  
  13.     array [0] = "foo"  
  14.     array [1] = "bar"  
  15.     s.string_array = array  
  16.     printStruct (&s)  
我们可以看出结构体也需要块分隔符,这里需要注意当你定义使用C中的类型时,需要明确的使用cdef关键字,告诉编译器你要的是C类型而不是PyObject类型。

注意当使用cdef定义结构体时不需要struct关键字,如上所示。


三:Python中使用C的枚举,typedef和函数指针

mycode.h文件:

[python] view plaincopy在CODE上查看代码片派生到我的代码片
  1. #ifndef __MYCODE_H__  
  2. #define __MYCODE_H__  
  3. typedef enum _cardsuit{  
  4.  CLUBS,  
  5.  DIAMONDS,  
  6.  HEARTS,  
  7.  SPADES  
  8. }cardsuit;  
  9. extern void printCard(cardsuit);  
  10. typedef void (*pcard)(cardsuit);  
  11. #endif  
mycode.c文件:

[python] view plaincopy在CODE上查看代码片派生到我的代码片
  1. #include "mycode.h"  
  2. void printCard(cardsuit c)  
  3. {  
  4.   switch(c)  
  5.   {  
  6.     case CLUBS:  
  7.             printf("CLUBS\n");  
  8.             break;  
  9.     case DIAMONDS:  
  10.             printf("DIAMONDS\n");  
  11.             break;  
  12.     case HEARTS:  
  13.             printf("HEARTS\n");  
  14.             break;  
  15.     case SPADES:  
  16.             printf("SPADES\n");  
  17.             break;  
  18.   }  
  19.     
  20. }  

在这里我们定义了一个枚举{梅花,方片,红桃,黑桃},定义了一个printCard函数打印传递的牌的花色,同时使用typedef给枚举定义了一个简单形式,且定义了形如printCard函数的函数指针。下面我们就通过Python来调用printCard函数和函数指针。

mycodepy.pyx文件:

[python] view plaincopy在CODE上查看代码片派生到我的代码片
  1. cdef extern from "mycode.h":  
  2.    enum _cardsuit:  
  3.     CLUBS,DIAMONDS,HEARTS,SPADES  
  4.    ctypedef  _cardsuit cardsuit  
  5.    void printCard(cardsuit)  
  6.    ctypedef void (*pcard)(cardsuit)  
  7.   
  8. def Pcard():  
  9.     cdef cardsuit card_c=CLUBS  
  10.     printCard(card_c)  
  11.     cdef cardsuit card_h=HEARTS  
  12.     cdef pcard p=&printCard  
  13.     p(card_h)  
  14.       
Cython中ctypedef等同于C的typedef,代码也比较简单易懂,分别用函数调用一次和函数指针调用一次,结果如下:



0 0