Python language extensions in combination with C

table of Contents

 

1. Python/C API

1.1 introduced Python.h

1.2 Packaging Function

1.3 Disclaimer List Module Methods

1.4 Module configuration defined

1.5 定义Module Initialization Method

1.6 establish Extension Module

2. ctypes

2.1 C language version of the program

2.2 The establishment of Shared Library

2.3 introduction Library

3. SWIG

Create a C language program version 3.1

3.2 establish Interface File

3.3 produces Wrapper File

3.4 Building Shared Library


1. Python/C API

First introduced the most basic way to achieve by Python / C API.

Python extension module is the Python language other than the official Python module Python established and can make calls, official documents Address: docs.python.org/3/extending... , suggest that you at the time of writing C extensions, all I read about.

First, to show you what version of Python Feibolaqi:

def fib_recursive(n):
    if n < 2:
        return n
    return fib_recursive(n - 1) + fib_recursive(n - 2)
    
start_ts = time.time()
print(fib_recursive(35))
print(time.time() - start_ts)

# 运行结果:
# 9227465
# 3.8501219749450684
复制代码

If this program was changed to C language program, named speedup_fib.c, how to be rewritten, requires the following steps:

1.1 introduced Python.h

Python / C API is a C language build Python extension module coal referral must be introduced Python.h header files.

// content of speedup_fib.c
#include <Python.h>

long long _fib(long long n){
    if(n < 2)
        return n;
    else
        return _fib(n-1) + _fib(n-2);
};
复制代码

The introduction Python.h, written language version of Feibolaqi a C.

1.2 Packaging Function

Everything in Python objects corresponding to the C language is PyObject, so to its original function package and let the parameters and return values are PyObject.

The official form provides three parameters:

  • (PyObject *self)
  • (PyObject *self, PyObject *args)
  • (PyObject *self, PyObject *args, PyObject *kwargs)

Where args represents positional arguments, kwargs is keyword arguments.

These arguments put Python in C language into their own definition of the parameters, then also need to call a few API, specifically refer to the official documentation docs.python.org/3/c-api/arg... screenshot below.

 

 

 

Common is two.

  • int PyArg_ParseTuple(PyObject *args, const char *format, ...)
  • int PyArg_ParseTupleAndKeywords(PyObject *args, PyObject *kw, const char *format, char *keywords[], ...)

The first treatment with conventional positional arguments, the second processing tape positional arguments and keyword arguments.

Wherein the formatformatted parameter types, such as integer or string length, and specifically refer to the official documentation: docs.python.org/2.0/ext/par...

Because the program does not Feibolaqi key parameters, so the use of the first function and parameters need to format a long integer, long integer query document is lrepresented.

According to the above explanation, after the final wrapper is:

// content of speedup_fib.c
static PyObject *fib(PyObject *self, PyObject *args) {

   long long n; // 定义 参数

   long long res; // 定义返回值
   
   // 将参数进行包装,并格式化为长整型l,如果包装失败,则返回NULL.
   if (!PyArg_ParseTuple(args, "l", &n))
       return NULL;
   // 调用C语言版本的斐波拉契,同时传入包装好的参数n
   res = _fib(n);
   // 将返回值用  Py_BuildValue 包成 PyObject 传给 Python
   return Py_BuildValue("l", res);
};
复制代码

Feibolaqi function is defined as the packaging fib, and finally return value also needs to be packed, the return value is packed into C language PyObject.

1.3 Disclaimer List Module Methods

After the function module is packaged one by one, to establish this list method module, the purpose is to declare a package correspondence between each function and function of the C language, which is the form and function of the incoming format:

{name, method, flags, doc}
即 {名称,包装函数,哪种argument形式, 描述}
复制代码

flags of identity can refer to the official document: docs.python.org/3/c-api/str...

More is METH_VARARGS and METH_KEYWORDS, respectively args and keywords.

Therefore, according to the above description Module Methods, defined as:

// content of speedup_fib.c
static PyMethodDef SpeedupFibMethods[] = {
    {"speedup_fib", (PyCFunction) fib, METH_VARARGS, "fast fib"},
    {NULL, NULL, 0, NULL} // 以 NULL 作结
};
复制代码

1.4 Module configuration defined

After establishing Module Methods, Module also need to define the structure of information is needed to create a module object. The format is:

{base, name, doc, size, module methods 表}
即 {PyModuleDef_HEAD_INIT, 名字, 描述, 分配内存大小, module 方法列表}
复制代码

Related definitions can refer to the official document: docs.python.org/3/c-api/mod...

According to the above description, the structure function is defined Module:

// content of speedup_fib.c
static struct PyModuleDef speedup_fib_module = {
    PyModuleDef_HEAD_INIT,
    "speedup_fib",
    "A module containing methods with faster fib.",
    -1, // global state
    SpeedupFibMethods
};
复制代码

1.5 定义Module Initialization Method

Next, define the Module Initialization Method, the purpose is to create a module object module based on structural information, and this module object can call for Python.

Note Module Initialization Method must begin PyInit_.

// content of speedup_fib.c
PyMODINIT_FUNC PyInit_speedup_fib() {
  return PyModule_Create(&speedup_fib_module);
}
复制代码

1.6 establish Extension Module

The above step 5 has the speedup_fib.ccode section of the finished, a need to create setup.py, by DistutilsModule C language is created out of the module.

# content of setup.py
from distutils.core import setup, Extension
speedup_fib_module = Extension('speedup_fib', sources=['speedup_fib.c'])

setup(
    name='SpeedupFib',
    description='A package containing modules for speeding up fib.',
    ext_modules=[speedup_fib_module],
)
复制代码

Which method C program which is specified first, and then call setup to establish extension file.

By the following command:

python3 setup.py build_ext --inplace
复制代码

In the current folder will establish a speedup_fib.cpython-37m-darwin.so, then it can be called from Python files directly.

have a test:

from speedup_fib import speedup_fib
start_ts = time.time()
print(speedup_fib(35))
print(time.time() - start_ts)

# 运行结果:
# 9227465
# 0.054654836654663086
复制代码

Before contrast Python program, 80 times faster, if n is greater, the speed gap will be even greater.

2. ctypes

If you think the first way too cumbersome, then introduce ctypes, ctypes is provided by a libray Python, Python allows access external dynamic-link library (DLL) or shared library to call functions.

This eliminates the need to focus on API Python associated with C, and C function to focus on writing.

2.1 C language version of the program

This step can not in any way in the province, above all, written in C language version of the program.

// content of speedup_fib.c
long long fib(long long n){
    if(n < 2)
        return n;
    else
        return fib(n-1) + fib(n-2);
};
复制代码

Is not very simple, only need to focus write functions, header files do not even need.

2.2 The establishment of Shared Library

This step need to use gcc tool, and if not, you need to install.

gcc -shared -fPIC speedup_fib.c -o speedup_fib.so
复制代码

By the above-described command speedup_fib.c speedup_fib.so produce a file.

2.3 introduction Library

Next is simple, just ctypes ways to improve, the introduction of speedup_fib.so file, then you can run a Python.

# content of fib.py

from ctypes import *
func = cdll.LoadLibrary('./speedup_fib.so')

start_ts = time.time()
print(func.fib(35))
print(time.time() - start_ts)
复制代码

Run the above file fib.py get results:

9227465
0.06056809425354004
复制代码

3. SWIG

SWIG (Simplified Wrapper and Interface Generator) is more general and comprehensive tool that supports Python, Perl, Ruby and other languages.

First you need to install SWIG, if the environment is directly mac brew install swigcan, window environment with reference to the official website: www.swig.org/Doc3.0/Pref...

Create a C language program version 3.1

This step is essential, but there needs to swig command header files .h.

// content of speedup_fib.h
long long fib(long long n){
    if(n < 2)
        return n;
    else
        return fib(n-1) + fib(n-2);
};
复制代码

3.2 establish Interface File

Next to interface file, it can be said description file interface, used to be named * .i or * .swg.

Next, define a speedup_fib.i

// content of speedup_fib.i

/* 定义 module名称 */
%module speedup_fib

/*导入定义的 speedup_fib.h*/
%{
#include "speedup_fib.h"
%}
/* 告诉 SWIG 定义的 function 或 variable */
long long fib(long long n);
复制代码

As defined above speedup_fib.i, the first step in defining Module name, the second step of the introduction of the definition speedup_fib.h, which calls the function inside swig, the third step is to declare a function.

3.3 produces Wrapper File

SWIG generated by the Interface File speedup_fib_wrap.c extension module of speedup_fib.py and the wrapper file.

Command is as follows:

swig -python speedup_fib.i
复制代码

The current folder will be more than two files: speedup_fib.py and speedup_fib_wrap.c.

3.4 Building Shared Library

This step with Python / C to create an extension module API, with the establishment of shared library and use setup.py Distutils:

# content of setup.py

from distutils.core import setup, Extension

# Extension module name 要有底线前缀
speedup_fib_module = Extension('_speedup_fib', sources=['speedup_fib_wrap.c'])
setup(
    name='SpeedupFib',
    description='A package containing modules for speeding up performance.',
    ext_modules=[speedup_fib_module],
)
复制代码

Note Extension module name prefix must be the bottom line.

Then the following command:

python3 setup.py build_ext --inplace
复制代码

In the current folder will establish a _speedup_fib.cpython-37m-darwin.so, then it can be called from Python files directly.

# content of fib.py

from speedup_fib import fib

start_ts = time.time()
print(fib(35))
print(time.time() - start_ts)
复制代码

Run fib.py, operating results as follows:

9227465
0.05449485778808594

 

Guess you like

Origin blog.csdn.net/ytp552200ytp/article/details/93467230