c 调用python库_[学习Cython编程]C中使用Python标准库

Python的库非常丰富,如果能在C中使用Python的一些库,无疑是很让人兴奋的,下面我们就将在C中使用Pyhton的urllib模块和logging模块。

在C中调用Python需要包含整个Python的运行时库,链接模型如下:

在C/C++中嵌入Python代码是非常简单的,下面是代码模板:

#include 

int main(int argc,char** argv)

{

Py_SetProgramName(argv[0]);

Py_Initialized();

/* Do all your stuff in side here... */

Py_Finalize();

return 0;

}

注意“Pyhon.h"头文件需要首先被包含。

我们通过下面几个例子学习如何嵌入Python代码:

一:urllib

Python关于网络方面的库相当丰富,我们将在C中调用urllib.urlopen获取网页内容。

url.pyx文件:

import urllib

cdef public char * open(char * url):

content=urllib.urlopen(url).read()

return contentpublic是Cython的关键字,代表这个函数被导出,所以Cython会自动创建url.c和url.h,url.h就是用来被C/C++代码包含的,Cython做的非常智能。

Python中的字符串对应的就是C中的char*,所以我们参数为char*,同时返回内容也为char*,Cython将自动帮我们完成类型转换。

我们来看看Cython自动产生的url.h头文件,我们将在主文件中包含它。

url.h文件:

#ifndef __PYX_HAVE__url

#define __PYX_HAVE__url

#ifndef __PYX_HAVE_API__url

#ifndef __PYX_EXTERN_C

#ifdef __cplusplus

#define __PYX_EXTERN_C extern "C"

#else

#define __PYX_EXTERN_C extern

#endif

#endif

__PYX_EXTERN_C DL_IMPORT(char) *open(char *);

#endif /* !__PYX_HAVE_API__url */

#if PY_MAJOR_VERSION 

PyMODINIT_FUNC initurl(void);

#else

PyMODINIT_FUNC PyInit_url(void);

#endif

#endif /* !__PYX_HAVE__url */这里面主要有两个函数,一个是我们用public关键字导出的open函数,另外一个在Python2平台上是initurl函数,这将初始化我们的模块。注意:”initurl"中的“url"就是我们的文件名,在Python中也就是模块。

下面我们将在C中调用open函数,代码为:

main.c文件:

#include 

#include "url.h"

int main (int argc, char ** argv)

{

/* Boiler plate init Python */

Py_SetProgramName (argv [0]);

Py_Initialize ();

/* Init our url module into Python memory */

initurl();

if (argc >= 2)

{

/* call directly into our cython module */

printf("%s",open(argv[1]));

}

else

printf ("require url...\n");

/* cleanup python before exit ... */

Py_Finalize ();

return 0;

}我们只是简单的在C中打印出open的获取结果,注意先调用初始模块函数,然后在调用模块中可用方法。

Makefile文件如下:

all:

cython url.pyx

gcc -g -O2 -fpic -c url.c -o url.o `python-config --includes`

gcc -g -O2 -fpic -c main.c -o main.o `python-config --includes`

gcc -g -O2 -o example main.o url.o `python-config --libs`

clean:

rm -f example url.c *.o我们看看运行结果:

很强大吧,有了Cython咱再也不怕C的标准库功能单一了。

认真看代码的童鞋对url.pyx可能会有疑惑,为什么不直接return呢,加个零时变量做啥,这是有原因的:

import urllib

cdef public char * open(char * url):

return urllib.urlopen(url).read()

如果url.pyx代码如上,编译产生错误:obtaining char* from temporary Python value

由于我们之间return将导致read()产生零时变量,当超出该函数作用域零时变量将被释放,导致我们返回的char*指针成为悬挂指针。

而当我们专门赋值为一变量时,将导致引用计数加一,变量生存周期也就在我们控制之下了。

二:logging

下面演示如何在C中使用Python的logging模块。

logger.pyx文件如下:

import logging

cdef public void initLogging (char * logfile):

logging.basicConfig (filename = logfile,

level = logging.DEBUG,

format = '%(levelname)s %(asctime)s: %(message)s',

datefmt = '%m/%d/%Y %I:%M:%S')

cdef public void pyinfo (char * message):

logging.info (message)

cdef public void pydebug (char * message):

logging.debug (message)

cdef public void pyerror (char * message):

logging.error (message)main.h头文件如下:

#ifndef __MAIN_H__

#define __MAIN_H__

#include 

#include 

#include 

#define printflike \

__attribute__ ((format (printf, 3, 4)))

extern void printflike cinfo (const char *, unsigned, const char *, ...);

extern void printflike cdebug (const char *, unsigned, const char *, ...);

extern void printflike cerror (const char *, unsigned, const char *, ...);

#define info(...)                               \

cinfo (__FILE__, __LINE__, __VA_ARGS__)

#define error(...)                              \

cerror (__FILE__, __LINE__, __VA_ARGS__)

#define debug(...)                              \

cdebug (__FILE__, __LINE__, __VA_ARGS__)

#include "logger.h"

#endif //__MAIN_H__main.h头文件主要对man.c中函数的封装,自动传递文件名和行号。里面使用了变长参数,并且使用了GCC的__attrribute__特性。

#define printflike __attribute__ ((format (printf, 3, 4)))说明后面格式化字符串使用printf函数格式,并且变长参数从第三个参数开始,这更多的是让GCC可在编译阶段发现错误。

mian.c文件如下:

#include "main.h"

void cinfo (const char * file, unsigned line,

const char * fmt, ...)

{

char buffer [256];

va_list args;

va_start (args, fmt);

vsprintf (buffer, fmt, args);

va_end (args);

char buf [512];

snprintf (buf, sizeof (buf), "%s-%i -> %s",

file, line, buffer);

pyinfo (buf);

}

void cdebug (const char * file, unsigned line,

const char * fmt, ...)

{

char buffer [256];

va_list args;

va_start (args, fmt);

vsprintf (buffer, fmt, args);

va_end (args);

char buf [512];

snprintf (buf, sizeof (buf), "%s-%i -> %s",

file, line, buffer);

pydebug (buf);

}

void cerror (const char * file, unsigned line,

const char * fmt, ...)

{

char buffer [256];

va_list args;

va_start (args, fmt);

vsprintf (buffer, fmt, args);

va_end (args);

char buf [512];

snprintf (buf, sizeof (buf), "%s-%i -> %s",

file, line, buffer);

pyerror (buf);

}

int main (int argc, char ** argv)

{

/* Boiler plate init Python */

Py_SetProgramName (argv [0]);

Py_Initialize ();

/* Init our config module into Python memory */

initlogger ();

if (argc >= 2)

{

/* call directly into our cython module parseConfig */

initLogging (argv [1]);

info ("info message");

debug ("debug message");

error ("error message");

}

else

printf ("require path to output logfile...\n");

/* cleanup python before exit ... */

Py_Finalize ();

return 0;

}

我们来看看运行结果:

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值