【Python】使用C语言来扩展Python模块

在做毕业设计的时候,我用Python来实现项目的应用层,底层的驱动由于对时间要求比较严格(微秒级),用Python会出问题,毕竟Python就不是用来做底层开发的。这就涉及到在Python中使用C程序的问题,下面给出几种解决方案。

commands模块

使用这个模块,我们可以执行一些外部程序,并且获取其返回值以及执行状态,如

status, output = commands.getstatusoutput("sudo ./main")

但是这种方式的局限性比较大,必须等待外部程序执行完毕才能继续执行,外部模块之间难以完成通信。优点是几乎可以融合任何语言编写的可执行程序。


ctypes

这个模块可以加载dll(Windows)或者so(Linux),并且执行其中的函数,另外,它也提供了一些数据类型,这些类型与C语言中的基本数据类型一一对应,甚至提供了指针的使用,缺点是如果你的动态链接库依赖与第三方的库,那么将没有办法使用。详情参见ctypes — A foreign function library for Python


Python模块

要编写Python的模块,需要对我们编写的C程序做一层封装,从而让Python可以顺利与C模块通信。虽然说起来很高大上,但是做起来并不困难,由于我也不太熟悉一些专业术语,直接上模板了。详细的文档参见Extending Python with C or C++以及Building C and C++ Extensions with distutils

/* Example of embedding Python in another program */

#include "Python.h"

void initxyzzy(void); /* Forward */

main(int argc, char **argv)
{
    /* Pass argv[0] to the Python interpreter */
    Py_SetProgramName(argv[0]);

    /* Initialize the Python interpreter.  Required. */
    Py_Initialize();

    /* Add a static module */
    initxyzzy();

    /* Define sys.argv.  It is up to the application if you
       want this; you can also leave it undefined (since the Python
       code is generally not a main program it has no business
       touching sys.argv...) 

       If the third argument is true, sys.path is modified to include
       either the directory containing the script named by argv[0], or
       the current working directory.  This can be risky; if you run
       an application embedding Python in a directory controlled by
       someone else, attackers could put a Trojan-horse module in the
       directory (say, a file named os.py) that your application would
       then import and run.
    */
    PySys_SetArgvEx(argc, argv, 0);

    /* Do some application specific code */
    printf("Hello, brave new world\n\n");

    /* Execute some Python statements (in module __main__) */
    PyRun_SimpleString("import sys\n");
    PyRun_SimpleString("print sys.builtin_module_names\n");
    PyRun_SimpleString("print sys.modules.keys()\n");
    PyRun_SimpleString("print sys.executable\n");
    PyRun_SimpleString("print sys.argv\n");

    /* Note that you can call any public function of the Python
       interpreter here, e.g. call_object(). */

    /* Some more application specific code */
    printf("\nGoodbye, cruel world\n");

    /* Exit, cleaning up the interpreter */
    Py_Exit(0);
    /*NOTREACHED*/
}

/* A static module */

/* 'self' is not used */
static PyObject *
xyzzy_foo(PyObject *self, PyObject* args)
{
    return PyInt_FromLong(42L);
}

static PyMethodDef xyzzy_methods[] = {
    {"foo",             xyzzy_foo,      METH_NOARGS,
     "Return the meaning of everything."},
    {NULL,              NULL}           /* sentinel */
};

void
initxyzzy(void)
{
    PyImport_AddModule("xyzzy");
    Py_InitModule("xyzzy", xyzzy_methods);
}

你的C代码需要以这个模板为框架,注意以下几点
1. xyzzy是你的模块的名称,其它地方不要修改,因为Python对于模块的命名有比较严格的规范,随意命名可能会出现问题。
2. 你的主体程序需要在xyzzy_foo这个函数中执行,当然也可以在这个函数中调用,这个函数将来会与模块的接口绑定,从而实现在Python中调用执行。
3. xyzzy_methods这个数组将你的模块的接口与内部函数对应起来,其中foo就是将来你在Python中调用的方法名。
4. initxyzzy用于初始化你的模块,基本主需要修改以下模块的名称即可
5. 主函数中有一些附加代码,比如获取命令行参数,如果不需要可以去除。

from distutils.core import setup, Extension

module1 = Extension('demo',
                    define_macros = [('MAJOR_VERSION', '1'),
                                     ('MINOR_VERSION', '0')],
                    include_dirs = ['/usr/local/include'],
                    libraries = ['tcl83'],
                    library_dirs = ['/usr/local/lib'],
                    sources = ['demo.c'])

setup (name = 'PackageName',
       version = '1.0',
       description = 'This is a demo package',
       author = 'Martin v. Loewis',
       author_email = 'martin@v.loewis.de',
       url = 'https://docs.python.org/extending/building',
       long_description = '''
This is really just a demo package.
''',
       ext_modules = [module1])

这个Python代码用于生成你的Python模块的动态链接库,它的作用实际上就是生成一条编译命令,理论上手动生成也是可以的,下面说几点注意事项:

  1. 在Extension中,你需要设置项目编译的一些具体信息,比如宏,头文件目录,库目录,依赖库的名称,以及模块的源代码路径。
  2. 如果你的C代码依赖于非C标准库,一定要设置依赖库的信息,否则在导入模块的时候会提示库中的函数未定义。
  3. 在setup中可以设置模块的一些属性信息,这个看个人情况设定

最后,你只需要执行以下命令,即可生成库

python setup.py build

使用以下命令将安装库,从而可以在任意地方使用

python setup.py install
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值