zoukankan      html  css  js  c++  java
  • 【Python】python扩展

    当python的基本功能无法满足要求。或者是为了保密源码(.py)、遇到性能瓶颈时,我们经常要扩展python,扩展语言能够是C/C++、Java、C#等。

    为python创建扩展须要三个基本的步骤:创建应用程序代码;利用样板来包装代码;编译与測试。

    1、 创建应用程序代码

    我们创建一个C代码PythonEx.c,实现两个函数fac()和reverse(),分别用来求阶乘和逆转字符串,test()函数是用来測试fac()和reverse()基本功能的。以防问题带入python。

    // PythonEx.c
    #include <stdio.h> 
    #include <stdlib.h> 
    #include <string.h> 
    
    int fac(int n) 
    { 
        if (n < 2) { 
            return (1); 
        } 
        else { 
            return (n) * fac(n - 1); 
        } 
    } 
    
    char* reverse(char *s) 
    { 
        register char t; 
        register char *p = s; 
        register char *q = (s + strlen(s) -1); 
    
        while (p < q) { 
            t = *p; 
            *p++ = *q; 
            *q-- = t; 
        } 
    
        return s; 
    } 
    
    int test() 
    { 
        char s[BUFSIZ]; 
    
        printf("3! = %d
    ", fac(3)); 
        printf("6! = %d
    ", fac(6)); 
        printf("9! = %d
    ", fac(9)); 
    
        strcpy(s, "abcdefg"); 
        printf("'abcdefg' after reversing is '%s'
    ", reverse(s)); 
        strcpy(s, "python"); 
        printf("'python' after reversing is '%s'
    ", reverse(s)); 
    
        return 0; 
    }

    2、 用样板包装代码

    样板是扩展代码与python解释器之间进行交互的桥梁,主要分为以下4步。

    a.包括python的头文件。
    找到python头文件位置并确保编译器的訪问权限,然后在代码中inlcude这个头文件,例如以下:

    #include “Python.h”

    b.为每个模块的每个函数添加一个型如PyObject* Module_func()的包装函数。
    这部分须要为全部想被python环境訪问的函数都添加一个静态的函数。函数的返回值类型为PyObject*,函数名前面要加上模块名和一个下划线。

    包装函数的用处就是先把python的值传递给C,然后调用我们想要调用的相关函数。当这个函数完毕要返回python的时候,把函数的计算结果转换成python的对象,然后返回给python。那么。在从python到C的转换就用PyArg_Parse*系列函数,在从C转到python的时候,就用Py_BuildValue()函数。


    以下我们包装fac()和reverse()函数,如果其模块名为CustomPy,例如以下:

    static PyObject* CustomPy_fac(PyObject *self, PyObject *args) 
    { 
        int num; 
        if (!PyArg_ParseTuple(args, "i", &num)) { // i i.e. int->int 
            return NULL; 
        } 
        return (PyObject*)Py_BuildValue("i", fac(num)); // i i.e. int->int 
    } 
    
    static PyObject* CustomPy_reverse(PyObject *self, PyObject *args) 
    { 
        char *orig_str; // original 
        char *dup_str; // reversed 
        PyObject *retval; 
        if (!PyArg_ParseTuple(args, "s", &orig_str)) { // s i.e. str->char* 
            return NULL; 
        } 
        retval = (PyObject*)Py_BuildValue( 
                "ss", // s i.e. char*->str 
                orig_str, 
                dup_str = reverse(strdup(orig_str))); // strdup 
        free(dup_str); // free after strdup 
        return retval; // return tuple(orig_str, dup_str) 
    }
    
    static PyObject* CustomPy_test(PyObject *self, PyObject *args) 
    { 
        test(); 
        return (PyObject*)Py_BuildValue(""); 
    }

    以下是Python和C/C++之间的数据格式——
    FormatCode PythonType C/C++Type
    s str char*
    z str/None char*/NULL
    i int int
    l long long
    c str char
    d float double
    D complex Py_Complex*
    o (any) PyObject*
    S str PyStringObject

    c.为每个模块添加一个型如PyMethodDef ModuleMethods[]的数组。

    static PyMethodDef CustomPyMethods[] = { 
        {"fac", CustomPy_fac, METH_VARARGS}, 
        {"reverse", CustomPy_reverse, METH_VARARGS}, 
        {"test", CustomPy_test, METH_VARARGS}, 
        {NULL, NULL}, 
    };

    完毕包装函数后。把他们添加到一个数组中,以便于python解释器能够导入并调用它们。

    每个数组都包括了函数在python中的名字、对应的包装函数的名字以及一个METH_VARARGS常量,这个常量表示參数以tuple形式传入。最后是一个NULL数组表示列表结束。

    d.添加模块初始化函数void initModule()

    void initCustomPy() 
    { 
        Py_InitModule("CustomPy", CustomPyMethods); 
    }

    这部分代码在模块被导入的时候被解释器调用。

    另外。创建扩展还能够先写包装代码,使用桩函数、測试函数或哑函数,在开发过程中慢慢地把这些函数用有实际功能的函数替换。

    3、编译与測试

    为了让新python扩展能被创建。须要把它们与python库放在一起编译,曾经可能要用到Makefile,如今使用distutils模块就能够了,能够方便地编译、安装和分发这些模块、扩展和包。仅仅需创建一个setup.py脚本即可。

    #!/usr/bin/env python 
    
    from distutils.core import setup, Extension 
    
    MOD = 'CustomPy' 
    setup(name = MOD, ext_modules = [Extension(MOD, sources = [PythonEx.c])])

    以下直接执行setup.py脚本来创建自己定义模块。或者是install到python环境里,终于会生成一个so文件,接着import这个模块就能够使用了。

    还有两点须要注意的是,python的垃圾自己主动回收策略是引用计数。以及线程安全操作,这些都能够添加到自己定义的模块中。

    上面的样例中用C扩展了Python,我们还能够用Java扩展Jython,使用C#或者VB .NET扩展IronPython。如果在win32下,python还能够使用其COM(市场名字为ActiveX)操作Microsoft Office。

  • 相关阅读:
    Go 语言简介(下)— 特性
    Array.length vs Array.prototype.length
    【转】javascript Object使用Array的方法
    【转】大话程序猿眼里的高并发架构
    【转】The magic behind array length property
    【转】Build Your own Simplified AngularJS in 200 Lines of JavaScript
    【转】在 2016 年做 PHP 开发是一种什么样的体验?(一)
    【转】大话程序猿眼里的高并发
    php通过token验证表单重复提交
    windows 杀进程软件
  • 原文地址:https://www.cnblogs.com/gccbuaa/p/7159025.html
Copyright © 2011-2022 走看看