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。

  • 相关阅读:
    This iPhone 6s is running iOS 11.3.1 (15E302), which may not be supported by this version of Xcode.
    vmware 里MAC 鼠标能移动 无法单击
    php获取微信的openid
    PHP 调试打印输出变量
    E0264 Unable to execute '"/usr/bin/codesign" ...'
    PHP 返回JSON
    小米手机安装证书
    CSS3:radial-gradient,径向渐变的使用方法
    CSS3:linear-gradient,线性渐变的使用方法
    CSS3:RGBA的使用方法
  • 原文地址:https://www.cnblogs.com/gccbuaa/p/7159025.html
Copyright © 2011-2022 走看看