http://blog.csdn.net/yueguanghaidao/article/details/23093981 2014 Python的库非常丰富,如果能在C中使用Python的一些库,无疑是很让人兴奋的,下面我们就将在C中使用Pyhton的urllib模块和logging模块。 在C中调用Python需要包含整个Python的运行时库,链接模型如下:
在C/C++中嵌入Python代码是非常简单的,下面是代码模板: - #include <Python.h>
- 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代码:
一:urllibPython关于网络方面的库相当丰富,我们将在C中调用urllib.urlopen获取网页内容。 url.pyx文件: - import urllib
-
- cdef public char * open(char * url):
- content=urllib.urlopen(url).read()
- return content
public是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 < 3
- 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 <Python.h>
- #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 <Python.h>
-
- #include <stdio.h>
- #include <stdarg.h>
-
- #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;
- }
我们来看看运行结果:
|