Linux下C调用Python

说明

想要在C程序中调用Python,要包含头文件Python.h,由于Python.h不在默认的搜索路径中,这里有两种方法解决:

1.在程序中包含Python.h的路径:

#include 

 PS:这个是默认的路径

2.链接时加上gcc的参数:

-I/usr/include/python2.7/


Makefile的编写


这里提供了一个Makefile的编写供参考:

CC = gcc
CFLAGS =  -g -Wall

TARGET = test
	
INC = -I/usr/include/python2.7/
LIB = -L/usr/lib -lpython2.7

all: clean $(TARGET)

test: test.o
	$(CC) -o $(TARGET) test.o $(LIB)
test.o: test.c
	$(CC) -c test.c $(CFLAGS)

clean:
	rm -rf *.o $(TARGET)

其中对python2.7.so动态库进行了链接



最简单的调用 


此种对Python的调用称为low level,应用于C程序中进行一些简单Python语句的调用。

#include "/usr/include/python2.7/Python.h"

void
deal_error(const char *str)
{
	fprintf(stderr, "%s\n", str);
	exit(EXIT_FAILURE);
}

int
main()
{
	//初始化Python解释器
	//任何C与Python的交互都需要在最开始调用此函数
	Py_Initialize();
	if(!Py_IsInitialized()) {
		deal_error("Cannot init Python interpreter!");	
	}

	//执行简单的Python的命令
	PyRun_SimpleString("print 'Hello World'");

	return 0;
}


进一步的调用 


这种调用称为high level,更多情况下,我们更需要这种方法来对自己编写、系统的模块和函数、第三方库进行调用。

test.c

#include "/usr/include/python2.7/Python.h"

void
deal_error(const char *str)
{
	fprintf(stderr, "%s\n", str);
	exit(EXIT_FAILURE);
}

int
main()
{
	PyObject *p_name = NULL, *p_module = NULL, *p_dict = NULL,
		 *p_func = NULL;

	//初始化Python解释器
	//任何C与Python的交互都需要在最开始调用此函数
	Py_Initialize();
	if(!Py_IsInitialized()) {
		deal_error("Cannot init Python interpreter!");	
	}

	//执行简单的Python的命令
	//这里主要是在Python搜索文件的路径里加上当前路径
	//否则不能找到对应的文件,也就不能加载对应的模块
	PyRun_SimpleString("import sys");
	PyRun_SimpleString("sys.path.append('./')");

	//导入Python模块
	//对应的文件名,去掉py的后缀
	p_name = PyString_FromString("1");
	p_module = PyImport_Import(p_name);
	if(!p_module) {
		deal_error("Cannot load the module!");
	}

	//此函数获取模块中的函数列表
	p_dict = PyModule_GetDict(p_module);
	if(!p_dict) {
		deal_error("Cannot get the dict");
	}

	//查找函数的位置
	p_func = PyDict_GetItemString(p_dict, "hello");
	if(!p_func || !PyCallable_Check(p_func)) {
		deal_error("Cannot find the function");
	}

	//调用函数
	PyObject_CallObject(p_func, NULL);

	//指针的释放
	Py_DECREF(p_name);
	Py_DECREF(p_module);
	Py_DECREF(p_dict);
	Py_DECREF(p_func);

	//关闭Python
	Py_Finalize();
	return 0;
}

1.py:

PS: 名字不要起test.py,因Python中自带test模块,导入后自然找不到你自己创建的函数

#!/usr/bin/env python
#-*- coding: utf-8 -*-

def hello():
    print 'hello'


含有参数的调用


含有参数的调用比较复杂,除了涉及参数压栈等,还有C数据类型和Python数据类型转换的问题。这里只是简单的提了些用法。

 一个例子(后有详细说明):

test.c

#include "/usr/include/python2.7/Python.h"

void
deal_error(const char *str)
{
	fprintf(stderr, "%s\n", str);
	exit(EXIT_FAILURE);
}

int
main()
{
	PyObject *p_name = NULL, *p_module = NULL, *p_dict = NULL,
		 *p_func = NULL, *p_args = NULL;

	//初始化Python解释器
	//任何C与Python的交互都需要在最开始调用此函数
	Py_Initialize();
	if(!Py_IsInitialized()) {
		deal_error("Cannot init Python interpreter!");	
	}

	//执行简单的Python的命令
	//这里主要是在Python搜索文件的路径里加上当前路径
	//否则不能找到对应的文件,也就不能加载对应的模块
	PyRun_SimpleString("import sys");
	PyRun_SimpleString("sys.path.append('./')");

	//导入Python模块
	//对应的文件名,去掉py的后缀
	p_name = PyString_FromString("1");
	p_module = PyImport_Import(p_name);
	if(!p_module) {
		deal_error("Cannot load the module!");
	}

	//此函数获取模块中的函数列表
	p_dict = PyModule_GetDict(p_module);
	if(!p_dict) {
		deal_error("Cannot get the dict");
	}

	//查找函数的位置
	p_func = PyDict_GetItemString(p_dict, "add");
	if(!p_func || !PyCallable_Check(p_func)) {
		deal_error("Cannot find the function");
	}

	p_args = PyTuple_New(2);
	PyTuple_SetItem(p_args, 0, Py_BuildValue("i", 3));
	PyTuple_SetItem(p_args, 1, Py_BuildValue("i", 4));

	//调用函数
	PyObject_CallObject(p_func, p_args);

	//指针的释放
	Py_DECREF(p_name);
	Py_DECREF(p_module);
	Py_DECREF(p_dict);
	Py_DECREF(p_func);

	//关闭Python
	Py_Finalize();

	return 0;
}

1.py:

#!/usr/bin/env python
#-*- coding: utf-8 -*-

def add(a, b):
    print a+b

注意到主函数里的区别就是参数的压栈(因为add中没有返回值,有的情况待会讨论),首先PyTuple_New是新建一个参数的元祖,这个函数的参数是要建的元祖的长度。

PyObject* PyTuple_New( Py_ssize_t len);
 

之后就是设置每个参数,利用PyTuple_SetItem

int PyTuple_SetItem( PyObject *p, Py_ssize_t pos, PyObject *o);


p是要设置的参数元祖,也就是刚才新建的那个,pos是设置A元素的位置, o是所添加元素的值,这里涉及到Py_BuildValue的用法

Py_BuildValue主要是提供格式化的参数类型,例如整数,浮点数,字符串等。具体用法见:http://docs.python.org/release/1.5.2p2/ext/buildValue.html

当Python中函数有返回值的时候, 将调用函数的方式改成如下就可以:


        int ret;
	PyObject *p_retval = NULL;

	p_retval = PyObject_CallObject(p_func, p_args);
	PyArg_Parse(p_retval, "i", &ret);


文档

以上只是简单介绍,Python和C的类型互相转换还比较麻烦,详细函数:

通过C类型生成Python类型:

http://docs.python.org/release/1.5.2p1/api/node24.html

Python转换为C类型:

http://docs.python.org/2/c-api/concrete.html

C调用Python的官方文档:

http://docs.python.org/2/c-api/index.html

你可能感兴趣的:(Python)