"Python Coolbook" Cython

Source: Internet
Author: User
Tags gcd

GitHub Address

To import a library using Cython, you need a few files:

. c:c function Source code

. h:c function Header

. Pxd:cython function Header

. Pyx: Wrapper function

Setup.py:python

Examples of this section are: C and. h files with "Python Coolbook" using cTYPES to access C code _ _demo Advanced sample.c and sample.h two source files exist.

Cdef:cython function, can only be called in the Cython, Python cannot recognize the body behind this definition, and it is not only after the function, class, etc. can be defined by the definition of Def Python, in both pxd and Pyx can be used.

Csample.pxd:Cython Header File

The. pxd file contains only the C definition (similar to the. h file), which is the equivalent of wrapping the. h file as a Cython header. Note that. PXD is simply a declaration definition and we do not wrap the function at this time, which is done in. Pyx.

# csample.pxd## Declarations of "external" C functions and structurescdef extern from "sample.h":    int gcd (int, int) 
   bint In_mandel (double, double, int)    int divide (int, int, int *)    double avg (double *, int) Nogil    ctypedef str UCT point: Double         x         double y    double distance (point *, point *)

For example, we give the sample.h file as follows:

#ifndef __sample_h__#define __sample_h__#include <math.h> #ifdef __cplusplusextern "C" {#endifint gcd (int x, int y) ; int In_mandel (double x0, double y0, int n), int divide (int a, int b, int *remainder);d ouble avg (double *a, int n);    /* A C data structure */typedef struct Point {    double x, y;} Point;    Double distance (point *p1, point *p2), #ifdef __cplusplus} #endif #endif
Sample.pyx:Cython Package Body

The

program is as follows, the syntax in the Pyx text is consistent with Python, but you can specify the formal parameter type (or not) as in C, which is actually the most basic wrapper, and you can see that the function in the Csample package is called. We can see the strengthening of the basic packaging in the following article.

# sample.pyx# Import the low-level C Declarationscimport csample# Import some functionality from Python and the C STDLIBFR Om cpython.pycapsule cimport *from libc.stdlib cimport malloc, free# wrappersdef gcd (unsigned int x, unsigned int y): R Eturn csample.gcd (x, y) def in_mandel (x, y, unsigned int n): Return Csample.in_mandel (x, Y, N) def divide (x, y): cdef int rem quot = csample.divide (x, y, &rem) return quot, remdef avg (double[:] a): Cdef:int sz do uble result sz = a.size with Nogil:result = Csample.avg (<double *> &a[0], SZ) return result# De Structor for cleaning up point objectscdef del_point (Object obj): pt = <csample.  Point *> pycapsule_getpointer (obj, ' point ') free (<void *> PT) # Create a Point object and return as a capsuledef Point (Double x,double y): Cdef csample. Point *p p = <csample. Point *> malloc (sizeof (csample. Point)) If p = = Null:raise Memoryerror ("No memory to make a point") p.x = x p.y = y return pycapsule_new (<void *>p, "point", <pycapsule_destructor>del_point) def distance (P1, p2): pt1 = <csample. Point *> Pycapsule_getpointer (P1, "point") pt2 = <csample. Point *> Pycapsule_getpointer (P2, "point") return Csample.distance (PT1,PT2)

Since many of the details are contained in the code above, there are many advanced features described earlier, including array manipulation, wrapping of invisible pointers, and releasing the Gil, so the individual functions are analyzed below.

various situation function analysis gcd:简单的数字参数函数

csample.pxdThe file declares a int gcd(int, int) function sample.pyx in which the wrapper function is as follows:

Cimport csampledef gcd (unsigned int x, unsigned int y):  # <---unsigned reshape    return csample.gcd (x, y)

Unsigned integer makes it possible to receive a negative number in the run that will report the error of this line, we can modify the following

# def gcd (unsigned int x, unsigned int y): #     return csample.gcd (x, y) def gcd (int x, int y):    if x <= 0:        Raise ValueError ("x must is > 0")    if y <= 0:        raise ValueError ("Y must be > 0")    return csample.gcd (x, y)

As you can see, this is a good support for Python statements.

In_mandel: The return value is 0 or 1 (boolean shaping)
/* Test if (x0,y0) is in the Mandelbrot set or not */int In_mandel (double x0, double y0, int n) {    double x=0,y=0,xtemp ;    while (n > 0) {        xtemp = x*x-y*y + x0;        y = 2*x*y + y0;        x = xtemp;        n-= 1;        if (x*x + y*y > 4) return 0;    }    return 1;}

The PXD declaration can specify the function return type bint:

Bint In_mandel (double, double, int)

Divide: Parameter Pointer object
int divide (int a, int b, int *remainder) {    int quot = A/b;    *remainder = a% B;    return quot;}

Python can't deliver an address, but Pyx can ,

def divide (x, y):    cdef int rem    quot = csample.divide (x, y, &rem)    return quot, rem

Here, the rem variable is displayed as a c integer variable. When it is passed into divide() the function, &rem create a pointer to it like C.

AVG: Shape parameter group &gil release
/* Average values in an array */double avg (double *a, int n) {    int i;    Double total = 0.0;    for (i = 0; i < n; i++) {total        + = A[i];    }    return total/n;}

avg()the code for the function demonstrates the more advanced features of Cython:

def avg (double[:] a):    cdef:        int sz        double result    sz = A.size with    nogil:        result = Csample.avg (& Lt;double *> &a[0], SZ)    return result

First def avg(double[:] a) , you declare a avg() double-precision memory view that accepts one dimension. The most surprising part is that the returned result function can accept any compatible array object, including the one created by NumPy. For example:

>>>ImportArray>>>A=Array.Array(' d ',[1,2,3])>>>import numpy>>> b = numpy.  Array([1., 2., 3.]) >>> Import sample>>> sample.  Avg(a)2.0>>> sample.  Avg(b)2.0>>>           

In this wrapper, the a.size &a[0] number of array elements and the underlying pointers are referenced separately. Grammar <double *> &a[0] teaches you how to convert a pointer to a different type. The premise is that C avg() accepts a pointer of the correct type. Refer to the next section for more advanced narration about the Cython memory view.

In addition to working with the usual array, avg() This example shows how to handle the global interpreter lock.

    1. Statement with nogil: declares a block of code that can be executed without a Gil. In this block, there cannot be any ordinary Python object --only the cdef objects and functions declared as (PXD) can be used.
    2. In addition, external functions must be realistic to declare that they can execute without relying on the Gil. Therefore, in the Csample.pxd file, it avg() is declared as double avg(double *, int) nogil .
Distance, point: struct-body processing

This section uses a capsule object to treat a point object as a stealth pointer, as stated in Pxd,

ctypedef struct point:     double x     double y

First, the following imports are used to introduce functions defined in the C function library and the Python C API:

From Cpython.pycapsule Cimport *  # <---capsule structure function library, directly from Python C apifrom libc.stdlib cimport malloc, free

The packing is as follows, the structure is first established and finally returned in capsule form:

# destructor for cleaning up point objectscdef del_point (Object obj):    pt = <csample. Point *> pycapsule_getpointer (obj, "point")  # <---Capsule structure extraction pointer (capsule structure reduction structure) free    (<void *> PT) # Create A Point object and return as a capsuledef point (double x,double y):    cdef csample. Point *p    p = <csample. Point *> malloc (sizeof (csample. Point))    if p = = NULL:        raise Memoryerror ("No memory to make a point")    p.x = x    p.y = y    return pycapsule _new (<void *>p, "point", <pycapsule_destructor>del_point)

function del_Point() and Point() Use this function to create a capsule object that will wrap a Point  * pointer.

cdef  del_Point()will be del_Point() declared as a function that can only be accessed through Cython, not from Python. Therefore, this function is invisible to the outside-it is used as a callback function to clean up the memory allocated by the capsules. function calls, such as PyCapsule_New() PyCapsule_GetPointer() direct from the Python C API, are used in the same way.

distanceThe function Point() extracts the pointer from the created capsule object,

def distance (P1, p2):    pt1 = <csample. Point *> Pycapsule_getpointer (P1, "point")    pt2 = <csample. Point *> Pycapsule_getpointer (P2, "point")    return Csample.distance (PT1,PT2)

It is important to note that you do not need to worry about exception handling. If an incorrect object is passed in, PyCapsule_GetPointer() an exception is thrown, but Cython already knows how to find it and distance() pass it out.

One drawback of dealing with the point struct is that its implementation is not visible. You cannot access any properties to view the inside of it. Here's another way to wrap it, which is to define an extension type, as follows:

# sample.pyxcimport csamplefrom libc.stdlib cimport malloc, Free...cdef class Point:cdef Csample. Point *_c_point # Declares the point struct body def __cinit__ (self, double x, double y): # The initialization process is to build a struct Self._c_point = <CSA Mple. Point *> malloc (sizeof (csample. Point)) Self._c_point.x = x self._c_point.y = y def __dealloc__ (self): free (self._c_point) prop            Erty x: # method decorated as attribute Def __get__ (self): return self._c_point.x def __set__ (self, value): Self._c_point.x = Value Property y: # method decorated as attribute Def __get__ (self): return Self._c_point.y def __set__ (self, value): Self._c_point.y = valuedef distance (point P1, point P2): Return csample.distance (P1._c _point, P2._c_point) 

Here, the Cdif class Point declares a point as an extension type. The Class Property cdef csample.Point *_c_point declares an instance variable that has a pointer to the underlying point struct body. __cinit__()and __dealloc__() methods to pass through malloc() and free() create and destroy the underlying C struct. The declaration of the X and Y properties allows you to get and set the property values of the underlying struct body. distance()wrapper can also be modified so that it accepts Point an extended type instance as a parameter and passes the underlying pointer to the C function.

With this change, you will find it more natural to manipulate the point object:

>>>ImportSample>>>P1=Sample.Point(2,3)>>>P2=Sample.Point (4,5) > >> p1<sample. Point object at 0x100447288>>>> p2<sample. Point object at 0x1004472a0>>>> p1. X2.0>>> p1. Y3.0>>> sample. Distance (p1,p2) 2.8284271247461903>>>          
setup.py
From Distutils.core import setupfrom distutils.extension import extensionfrom cython.distutils import Build_extext_ modules = [    Extension (' sample ',              [' Sample.pyx '],              libraries=[' sample '),              library_dirs=['. ')] Setup (  name = ' Sample extension module ',  cmdclass = {' Build_ext ': Build_ext},  ext_modules = ext_modules)
Compile run

Python setup. PY build_ext --inplace

Note that the sample.c file will be modified to add many statements after compilation, so remember to back it up.

"Python Coolbook" Cython

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.