能够使用C语言编写扩展是Python一大卖点吧,这可以将一些关键的代码使用C来写以提升程序的性能。本文是参考了Python的官方文档整理而来的,同时结合了Python2跟Python3。按照惯例现在先从一个Hello World开始讲解一下写扩展的基本流程。

详细的内容可以参考官方文档:

https://docs.python.org/2.7/extending/index.html

https://docs.python.org/3/extending/index.html

https://docs.python.org/2.7/c-api/index.html

https://docs.python.org/3/c-api/index.html

同时本文中的示例代码可从 https://github.com/wusuopu/python-c-extension-sample 获取到。

首先介绍一下我当前的开发环境:

* ArchLinux

* gcc 4.8.2

* glibc 2.19

* Python 2.7.6

* Python 3.3.5

开始

先创建一个新的C代码文件 lc_hello.c。为了能够正常使用python的api,需要导入Python.h这个头文件。

#include

然后再定义一个模块的初始化函数。

PyMODINIT_FUNC initlc_hello_world(void)

{

Py_InitModule("lc_hello_world", lc_hello_world_methods);

printf("init lc_hello_world module\n");

}

这个函数是用于模块初始化的,即是在第一次使用import语句导入模块时会执行。其函数名必须为initmodule_name这样的格式,在这里我们的模块名为lc_hello_world,所以函数名就是initlc_hello_world。

在这个函数中又调用了Py_InitModule函数,它执行了模块初始化的操作。Py_InitModule函数传入了两个参数,第一个参数为字符串,表示模块的名称;第二个参数是一个PyMethodDef的结构体数组,表示该模块都具有哪些方法。与Py_InitModule相似的方法还有Py_InitModule3和Py_InitModule4。因此在initlc_hello_world方法之前还需要先定义 lc_hello_world_methods 数组。

static PyMethodDef lc_hello_world_methods[] = {

{"test", (PyCFunction)test_function, METH_NOARGS, "lc_hello_world extending test"},

{"add", (PyCFunction)add_function, METH_VARARGS, NULL},

{NULL, NULL, 0, NULL}

};

PyMethodDef结构体有四个字段。

* 第一个是一个字符串,表示在Python中对应的方法的名称;

* 第二个是对应的C代码的函数;

* 第三个是一个标致位,表示该Python方法是否需要参数,METH_NOARGS表示不需要参数,METH_VARARGS表示需要参数;

* 第四个是一个字符串,它是该方法的__doc__属性,这个不是必须的,可以为NULL。

PyMethodDef结构体数组最后以 {NULL, NULL, 0, NULL}结尾。(感觉好像不是必须的,但是通常都这么做那我们也这么做吧)

注意

:以上的用法都是针对Python2的,在Python3中又有些不同。

在Python3中模块的初始化函数的函数名变为了PyInit_module_name这样的形式了,因此这里就需要定义一个函数 PyMODINIT_FUNC PyInit_lc_hello_world。并且还需要返回一个 module 类型的变量。

其次在Python3中创建module对象的函数也由 Py_InitModule 变为了 PyModule_Create。

因此在Python3中模块的初始化函数应该定义如下:

PyMODINIT_FUNC PyInit_lc_hello_world(void)

{

PyObject *m;

m = PyModule_Create(&lc_hello_world_module);

if (m == NULL)

return NULL;

printf("init lc_hello_world module\n");

return m;

}

PyModule_Create函数需要传入一个 PyModuleDef 类型的指针。

因此在此之前还需要先定义 lc_hello_world_module 变量。

static struct PyModuleDef lc_hello_world_module = {

PyModuleDef_HEAD_INIT,

"lc_hello_world",/* name of module */

NULL,/* module documentation, may be NULL */

-1, /* size of per-interpreter state of the module, or -1 if the module keeps state in global variables. */

lc_hello_world_methods /* A pointer to a table of module-level functions, described by PyMethodDef values. Can be NULL if no functions are present. */

};

在 lc_hello_world_methods 中我们为模块指定了两个方法,接下来我们需要实现这两个方法。

static PyObject* test_function(PyObject *self)

{

PyObject_Print(self, stdout, 0);

printf("lc_hello_world test\n");

Py_INCREF(Py_True);

return Py_True;

}

这段代码定义了Python的test方法所对应的C函数。在这个函数中就只执行了一条printf语句,然后就返回了Py_True。

Py_True即是Python中的True,Py_INCREF函数执行的操作是对Python对象的计数引用值进行加1。与Py_INCREF对应的是Py_DECREF,它是对计数引用减1,并且计数引用为0时就销毁对象并回收内存。

static PyObject* add_function(PyObject *self, PyObject *args)

{

int num1, num2;

PyObject *result=NULL;

if (!PyArg_ParseTuple(args, "nn", &num1, &num2)) {

printf("传入参数错误!\n");

return NULL;

}

result = PyInt_FromLong(num1+num2);

return result;

}

这须代码定义了Python的add方法所对应的C函数。该函数需要传入两个整数类型的参数。

PyArg_ParseTuple是对传入的参数进行解析,关于这个函数的说明请查看Python手册。

注意

:在Python3中整数都是 long 类型的,因此这里的 PyInt_FromLong 需要改为 PyLong_FromLong,其作用是将C的int类型转为Python的int类型。

编译

扩展模块编写完成后,接下来就是对其进行编译了。先编写一个 setup.py 脚本。

#!/usr/bin/env python

#-*- coding:utf-8 -*-

from setuptools import setup, Extension

hello_world = Extension('lc_hello_world', sources=["lc_hello.c"])

setup(ext_modules=[hello_world])

然后再执行命令进行编译:

$ python setup.py build

执行成功后会在当前目录下的build目录中生成扩展模块文件。

测试

最后就是编写一个小程序来测试刚刚的模块是否可用。

import lc_hello_world

print(lc_hello_world.test.__doc__)

print(lc_hello_world.add.__doc__)

print(lc_hello_world.test())

print(lc_hello_world.add(1, 2))

print(lc_hello_world.add(1, '2')) # 这个会报错

C语言编写Python包,使用C语言编写Python扩展1——Hello World相关推荐

  1. 纯Python包发布setup脚本编写示例

    纯Python包发布setup脚本编写示例 2014 年 6 月 23 日IT.PythonIT.python 如果你有多个模块需要发布,而它们又存在于多个包中,那么指定整个包比指定模块可能要容易地多 ...

  2. 从官网下载的python包如何使用-如何下载python包

    pip 是 Python 包管理工具,该工具提供了对Python 包的查找.下载.安装.卸载的功能. 一般情况 pip 对应的是 Python 2.7,pip3 对应的是 Python 3.x. 部分 ...

  3. python和易语言抓包_易语言调用抓包工具 易语言网页抓包教程

    如何用易语言在手机上进行编程?需要用什么软件? 目前,有许多编程语言.当然,所有的句子都是由简单的英语单词组成的,而汉字是唯一简单的语言. 建议您也应该先学习C语言,开始学习if else,while ...

  4. win10安装python包imgaug报错Command python setup.py egg_info failed with error code 1 in C:\Users\admi

    提示Command "python setup.py egg_info" failed with error code 1 in C:\Users\admi 发现是安装shapel ...

  5. 从官网下载的python包如何使用-如何使用Python从需要登录信息的网站下载文件?...

    我正在尝试使用Python从一个网站下载一些数据.如果只是复制并粘贴url,除非您填写登录信息,否则它不会显示任何内容.我有登录名和密码,但是如何在Python中包含它们呢? 我现在的代码是:impo ...

  6. r语言必学的十个包肖凯_30 天学会R DAY 14:R语言必学包dplyr

    原标题:30 天学会R DAY 14:R语言必学包dplyr 第14天 R语言必学包dplyr R语言非常讲究数据的整理,我们在7-13天的R语言学习内容中,着重都是关于R语言的整理,各种方法对数据进 ...

  7. Python——常用Python包的学习笔记

    1 致谢 感谢陈助教的帮助! 2 前言 今天想通过画图展现一下学习参考值的变化情况,在网上看了一下,需要使用plt包,不过又忘了plt是做什么用的了,于是想要记录一下,写一下关于常用Python包的笔 ...

  8. 手把手教你发布一个Python包

    本文主题如下: 编写一个包(Python 源代码),但不是本文的重点. 编译包,观察编译后的文件. 发布包,发布的包可以有多种类型. 如何在 Pypi 中查看已发布的包. 注意: 本文编写的包在 Py ...

  9. python使用pip安装包_12.2.1 使用pip安装Python包

    12.2.1 使用pip安装Python包 大多数较新的Python版本都自带pip,因此首先可检查系统是否已经安装了pip.在Python 3中,pip有时被称为pip3. 1. 在Linux和OS ...

最新文章

  1. DotNet的JSON序列化与反序列化
  2. 和富友牵手与世界同步—高端体育时尚服装品牌的高标准伙伴
  3. java servlet helloworld,Java如何创建HelloWorld Servlet?
  4. Plate impulse response spatial interpolation with sub-Nyquist sampling
  5. 微软AJax.net源码初步分析(2)--服务执行流程
  6. 台达服务器型号,台达网络服务器机柜 42u 600宽 1200 2000mm SR1160标准机柜
  7. html 英文字母不换行,css如何设置英文单词不换行?
  8. 男友升级为老公的时候
  9. android代码删除wifi,Android Wifi的forget()操作实例详解_Android_脚本之家
  10. ubuntu 安装ssh 服务
  11. ISO7637-2测试case汇总
  12. 用Multisim对高频丙类谐振功率放大器进行仿真
  13. 易飞ERP PLM集成 解决方案
  14. python判断英文字母_python判断字符串中是否含有英文 | 张先生博客
  15. python3 进程池Pool 详解
  16. SOCKET实现广播(BoardCast)的发送和接收 (转)
  17. 汇编指令: JO、JNO、JB、JNB、JE、JNE、JBE、JA、JS、JNS、JP、JNP、JL
  18. @value读取不到数据库配置文件里的值的解决办法
  19. 力天创见客流统计设备应用分析
  20. 将字符串中的空字符全部替换为别的字符串 Python 版

热门文章

  1. 西安的IT要怎么才能发展?
  2. 川崎机器人几百个示教点位置的动态修正
  3. 川崎机器人总线通信_川崎机器人:PLC有那些功能?能实现机器人哪些通讯?
  4. 漫谈程序员(十五)——应届毕业生上海市落户政策解读
  5. 【BDTC 2016】大数据云服务论坛:云上的大数据探索
  6. 手把手教如何搭建一个百度网盘目录站点【保姆级】
  7. 论文阅读笔记《USAC: A Universal Framework for Random Sample Consensus》
  8. NBIOT模组M5310接入OneNET平台
  9. windows系统重装(安装)第一篇——老毛桃本地PE环境的安装
  10. 云原生时代的业务流程编排