项目地址:https://github.com/spin6lock/python-sproto

第一次写Python的C扩展,留点笔记记录一下。主要的参考文档是:Extending Python with C/C++, 之前也看过cython,但是用Python语法写C还是没学会,稍后再尝试用cython写一遍看看。

作为一个C扩展,是以Module的方式import进去代码里使用的,所以需要注册一下,把自己的接口告诉Python解释器。代码如下图:

static PyMethodDef pysproto_methods[] = {
{"sproto_create", py_sproto_create, METH_VARARGS},
{"sproto_type", py_sproto_type, METH_VARARGS},
{"sproto_encode", py_sproto_encode, METH_VARARGS},
{"sproto_decode", py_sproto_decode, METH_VARARGS},
{"sproto_pack", py_sproto_pack, METH_VARARGS},
{"sproto_unpack", py_sproto_unpack, METH_VARARGS},
{"sproto_protocol", py_sproto_protocol, METH_VARARGS},
{NULL, NULL}
}; PyMODINIT_FUNC
initpysproto(void){
PyObject *m;
m = Py_InitModule("pysproto", pysproto_methods);
if (m == NULL) {
return;
}
SprotoError = PyErr_NewException("pysproto.error", NULL, NULL);
Py_INCREF(SprotoError);
PyModule_AddObject(m, "error", SprotoError);
}
pysproto_methods是一个数组,每个元素是一个三元组{暴露给python的方法名,对应的C函数名,参数格式},以{NULL, NULL}表示结束。
init模块名(void)是一个特殊的函数,当Python里输入import 模块名的时候,C层就会调用 init模块名 来执行模块的初始化工作。Py_InitModule表示将上面的模块方法数组暴露给Python,下面的代码向模块注册了一个SprotoError,表明模块自带的异常类型。 Python传参数给C:
参见py_sproto_create,通过PyArg_ParseTuple函数接收参数。
    char *buffer;
int sz = ;
struct sproto *sp;
if (!PyArg_ParseTuple(args, "s#", &buffer, &sz)) {
return NULL;
}

ParseTuple有点像C的scanf,可以按指定格式读取函数的参数,还能自己设置异常,比如参数类型不对,参数个数不对之类的。所有暴露给Python解释器的C接口,只要返回NULL,解释器就知道你出错了,就会把设置好的异常抛出。

C需要返回给Python的,一般有int,string和指针三类。前面两类都可以通过Py_BuildValue解决,参考如下:

PyObject *data = Py_BuildValue("s#", (char*)value, length);

s#表示带长度参数的字符串,这样字符串里就可以包含结束符了。表示整型时,format参数用i。返回Py_BuildValue构建的PyObject指针,就能在Python代码里接收这个对象了。

如果要在不同的C函数之间传递C指针,则需要用到PyCapsule_New来建立一个Capsule,把C指针包起来。这个capsule可以指定名字,方便Python代码里打印。还可以指定destructor,当这个Capsule脱出当前scope,被gc回收的时候,就会调用destructor来析构。Python还贴心的提供了一个Context,用来给这个Capsule带上额外的数据,方便后续使用。

对于python-sproto来说,之前有个问题一直没处理好,sproto_type其实是对sproto的一个指针,指向其成员。所以,如果sproto被gc掉了,sproto_type就有可能出错。而且这个出错是取决于gc时机,如果gc没跑,sproto那块内存还在,就不会出错。这种隐藏的bug比较难查。简单来说,就是C扩展暴露给Python的对象,相互之间对生命周期有依赖关系。sproto_type依赖于sproto,所以sproto的生命周期至少应该和sproto_type一样长。为了向解释器说明这件事,需要用到Py_XINCREF和Py_XDECREF,当生成新的sproto_type的时候,给sproto调用Py_XINCREF,表示对sproto的引用加1,销毁的时候就在析构函数里减1,表示取消引用。

更优雅的做法,应该是把这类生命周期相关的信息,写在脚本里,而不是在C里处理。对外提供的可以是一个Python的类,这个类自己管理相关对象的生命周期,只要这个类还在,就能保证生命周期正确。

为sproto添加python绑定的更多相关文章

  1. 在Caffe添加Python layer详细步骤

    本文主要讨论的是在caffe中添加python layer的一般流程,自己设计的test_python_layer.py层只是起到演示作用,没有实际的功能. 1) Python layer 在caff ...

  2. sublime3添加python编译系统

    好记性不如烂笔头 为sublime3添加python编译系统,这里使用的anonconda2中的python.exe(即python2.7版本) 步骤: (1)打开sublime,打开“工具-> ...

  3. caffe添加python数据层

    caffe添加python数据层(ImageData) 在caffe中添加自定义层时,必须要实现这四个函数,在C++中是(LayerSetUp,Reshape,Forward_cpu,Backward ...

  4. 在eclipse添加第一次添加Python项目时,提示: Project interpreter not specified

    按图片操作,添加Python的路径,就能解决该问题

  5. Vim 8.0 版本安装方法及添加Python支持

    利用Git安装 最简单也是最有效的方法 1. 获取Vim仓库: git clone https://github.com/vim/vim.git 2. 升级到最新的版本: cd vim git pul ...

  6. Jenkins持续集成_02_添加python项目&设置定时任务

    前言 自动化测试脚本编写后,最终目的都是持续集.持续集成可以实现一天多次部署运行自动化脚本,对功能进行不断监控测试.由于小编使用python编写的自动化脚本,这里仅讲解下如何在Jenkins中添加py ...

  7. jQuery添加html绑定事件

    jQuery添加html绑定事件 $("#xxx").on("click",".dev",function(){ });

  8. eclipse中添加python开发环境

    由于自己一直使用的是eclipse这个IDE,在写spark,java等都是用它,主要是用它比较顺手,也并不是觉得它有什么特别好的之处.下面主要介绍一下,在window系统下,eclipse中搭建py ...

  9. Python绑定方法,未绑定方法,类方法,实例方法,静态方法

    >>> class foo(): clssvar=[1,2] def __init__(self): self.instance=[1,2,3] def hehe(self): pr ...

随机推荐

  1. 16.Linux配置环境变量和日志history和Terminal颜色和用户(IP)操作日志记录

    $ vim /etc/profile #####################环境变量################################# export TZ='Asia/Shangh ...

  2. C# 使用lock关键字lock不同的对象

    c# lock关键字的本质 是调用Monitor.Enter(object obj)并且在finally的时候调用Monitor.Exit(obj) 在obj是不同数据类型的时候会出现不同的情况 1. ...

  3. centos配置163源

    1.参考Centos镜像帮助 (1.1)备份原始repo shell> sudo mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/Ce ...

  4. 深入浅出设计模式——代理模式(Proxy Pattern)

    模式动机在某些情况下,一个客户不想或者不能直接引用一个对象,此时可以通过一个称之为“代理”的第三者来实现间接引用.代理对象可以在客户端和目标对象之间起到中介的作用,并且可以通过代理对象去掉客户不能看到 ...

  5. Html5 Canvas核心技术(图形,动画,游戏开发)--基础知识

    基础知识 canvas 元素可以说是HTML5元素中最强大的一个,他真正的能力是通过canvas的context对象表现出来的.该环境对象可以从canvas元素身上获得. <body> & ...

  6. Design pattern---观察者模式

    观察者模式:发布/订阅模式,当某对象(被观察者)状态发生改变时所有订阅该对象的观察者对象(观察者)都将更新自己 成员(4种): 1.抽象被观察者:将所有的观察者对象的引用存入一个集合,并且定义了添加 ...

  7. 第5章 Web自动化测试

    5.1 Selenium简介 5.1.1 自动化测试简介 5.1.2 Selenium简介 5.2 Selenium2环境搭建 5.3 Java基础 5.3.1 新建Java工程和类 5.3.2 Ec ...

  8. css样式设计

    1.行内元素(图片.文本)水平居中 通过给父元素设置 text-align:center html代码: <body> <div class="txtCenter" ...

  9. hdu ----3695 Computer Virus on Planet Pandora (ac自动机)

    Computer Virus on Planet Pandora Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 256000/1280 ...

  10. SqlParameter设定value为0却变成null

    直接MSDN:http://msdn.microsoft.com/zh-cn/library/0881fz2y(VS.80).aspx 当在 value 参数中指定 Object 时,SqlDbTyp ...