最近需要将库封装为python可调用的库。目前验证是可以直接使用静态库封装,如果想使用动态库,linux可以使用以下指令生成动态库。
ar -x mylib.a
gcc -shared *.o -o mylib.so
封装过程中遇到undefined reference to symbol '_ZTVN10__cxxabiv117__class_type_infoE类似问题,则需要将gcc改为g++就可以了。动态库的使用方法参考博客
以下所有问题都可以从python官网和中文链接中找到问题答案,封装过程中参考了这个博客
第一个问题:python如何保存c指针,便于后续使用?
PyObject* result = PyLong_FromVoidPtr((void*)info);
将指针通过PyLong_FromVoidPtr来生成pyobject,这样就可以保存指针值。在下次调用时,需要这样使用:
PyObject* info;
if (! PyArg_ParseTuple(args, "O", &info))
return NULL;
void* my_info = PyLong_AsVoidPtr(info);
通过pyarg_parsetuple的O选项将数值读出来,再通过PyLong_AsVoidPtr来获取之前保存的指针值。
第二个问题:如何获取python传递来的list内容?
PyObject* input_ptr;
if (! PyArg_ParseTuple(args, "O", &input_ptr))
return NULL;
先解析获取list的指针,然后通过PyObject_Length获取list长度。
int input_length = PyObject_Length(input_ptr);
for(int i = 0; i < input_length; i++)
{
PyObject* item;
item = PyList_GetItem(input_ptr, i);
if(!PyFloat_Check(item))
input_value[i] = 0.0;
input_value[i] = (float)(PyFloat_AsDouble(item));
}
通过pylist_getItem获取list内容,然后通过pyFloat_AsDouble将pyobject内容转换为需要的float值。
第三个问题:如何将C中的值以list形式传递出去?
这个问题和第二个问题相反。
PyObject* wrap_Get_Output(PyObject* self, PyObject* args)
{
PyObject* net_info;
int id, mem_size;
if (! PyArg_ParseTuple(args, "Oii", &net_info, &id, &mem_size))
return NULL;
info* my_info = (info*)(PyLong_AsVoidPtr(net_info));
float* output_ptr = (float*)my_info->output_buff[id];
PyObject* ret_val = PyList_New(mem_size);
int err = 0;
for(int i = 0; i < mem_size; i++)
{
PyObject* item;
item = PyFloat_FromDouble((double)output_ptr[i]);
err = PyList_SetItem(ret_val,(Py_ssize_t)i,item);
if(err == -1)
{
printf("SetItem Error: list length = %d, set index = %d\n",mem_size,i);
return NULL;
}
}
return ret_val;
}
先生成一个指定长度的list,然后将数据转换为pyobject,并将数据放入list中,该函数返回值为list。
第四个问题,如何通过关键字传递参数?
METH_VARARGS | METH_KEYWORDS
通过在methon设置key_words传递参数,例如:
{"test", (PyCFunction)wrap_test, METH_VARARGS | METH_KEYWORDS, "test"},
再通过PyArg_ParseTupleAndKeywords来解析参数,代码中设置kwlist表示关键字的列表。
PyObject* wrap_test(PyObject* self, PyObject* args, PyObject* kw)
{
int a,b,c;
char* kwlist[] = {"a","b","c", NULL};
if (! PyArg_ParseTupleAndKeywords(args,kw, "iii",kwlist, &a, &b, &c))
return NULL;
printf("a = %d, b = %d, c = %d\n", a,b,c);
return Py_BuildValue("ii", a+b,a+c);
}
以下代码测试可以看出确实是按照关键字传递参数了
(res1,res2)=nntest.test(b=1,c= 10,a=2)
print res1
print res2
当然如果在PyArg_ParseTupleAndKeywords的format"iii"中加|表示|后的参数都是可选参数;