官术网_书友最值得收藏!

Cython keyword – cdef

The cdef keyword tells the compiler that this statement is a native C type or native function. Remember from Chapter 1, Cython Won't Bite that we used this line to declare the C prototype function:

cdef int AddFunction(int, int)

This is the line that let us wrap the native C function into a Python callable using the Python def keyword. We can use this in many contexts, for example, we can declare normal variables for use within a function to speed up execution:

def square(int x):
    return x ** 2

This is a trivial example, but it will tell the compiler that we will always be squaring an integer. However, for normal Python code, it's a little more complicated as Python has to worry a lot more about losing precision when it comes to handling many different types. But in this case, we know exactly what the type is and how it can be handled.

You might also have noticed that this is a simple def function, but because it will be fed to the Cython compiler, this will work just fine, and handle the typed parameter as you would expect.

Structs

C structs can be worked with directly in Cython. For example, this header declares a simple struct:

#ifndef __MYCODE_H__
#define __MYCODE_H__

struct mystruct {
 char * string;
 int integer;
 char ** string_array;
};

extern void printStruct (struct mystruct *);

#endif //__MYCODE_H__

This random struct will demonstrate several concepts, including working with an array. Firstly, we must declare the layout of the struct inside Cython. We can again use the cdef block syntax. Everything within that block is a cdef and will include the specified header, which is important when the output from the Cython compiler is compiled via GCC or Clang:

cdef extern from "mycode.h":
 struct mystruct:
 char * string
 int integer
 char ** string_array
  void printStruct (mystruct *)

Now that we have declared the prototype printStruct function, we can use this to verify the data outside of Cython's scope. To work with this raw data type, we will make a testStruct Python callable, which we will invoke using a simple Python import:

def testStruct ():
 cdef mystruct s
 cdef char *array [2]
    s.string = "Hello World"
 s.integer = 2
    array [0] = "foo"
    array [1] = "bar"
    s.string_array = array
 printStruct (&s)

Let's look at this more closely. We firstly declare an instance of the struct on the stack. Next, we declare a C-String array of size 2. The next lines will look familiar via setting each of the members of the struct with a value. But notice that we declared our string array on the stack and then set the string array member to this instance. This is important as Cython will rely on the programmer to understand memory and stack versus heap properly. But it's important to notice that passing strings from language to language is completely trivial.

The final caveat with structs is while defining a cdef declaration for a function. If a parameter is a struct, you never declare it as follows:

  void myfunc (struct mystruct * x)

Instead, we simply use the following:

  void myfunc (mystruct * x)

Cython will figure it out.

There are a few subtleties with the testStruct function. In Cython, we have the reference operator '&' that works just as in C. Therefore, with this struct on the stack, we can pass a pointer via the reference operator just like in C.

Note that we don't have a '' operator in Cython. When accessing members inside the struct (even if it is a pointer), we simply use the '.' operator. Cython understands the context and will handle it.

From the previous example and for the sake of completeness we can implement the printStruct function simply as:

#include <stdio.h>
#include "mycode.h"

void printStruct (struct mystruct * s)
{
    printf(".string = %s\n", s->string);
    printf(".integer = %i\n", s->integer);
    printf(".string_array = \n");

    int i;
    for (i = 0; i < s->integer; ++i)
        printf ("\t[%i] = %s\n", i, s->string_array [i]);
}

This demonstrates even when we initialize the C struct from within Cython code it's a perfectly valid C type. A simple run of this in the downloaded code is as follows:

$ cd chapter2/cpy-cdef-reference
$ make
$ python
>>> from mycodepy import testStruct
>>> testStruct ()
.string = Hello World
.integer = 2
.string_array =
 [0] = foo
 [1] = bar

This demonstrates that Cython can work with C structs—it initialized the C struct and assigned its data members, as you would expect if it was from C.

Enums

Interfacing with C enums is simple. If you have the following enum in C:

enum cardsuit {
   CLUBS,
   DIAMONDS,
   HEARTS,
   SPADES
};

Then this can be expressed as the following Cython declaration:

cdef enum cardsuit:
  CLUBS, DIAMONDS, HEARTS, SPADES

Then, use the following as the cdef declaration within our code:

cdef cardsuit card = CLUBS

It's a very small example, but it's important to see how simple it is.

主站蜘蛛池模板: 吴江市| 庄河市| 金昌市| 永顺县| 正镶白旗| 汉寿县| 凤山市| 和平区| 得荣县| 班玛县| 武安市| 象山县| 义马市| 永靖县| 开化县| 余干县| 洛阳市| 恩施市| 高安市| 塔河县| 新野县| 上虞市| 芒康县| 宜州市| 双流县| 泸西县| 屯留县| 中西区| 宣威市| 襄城县| 屏东市| 应城市| 九江县| 康保县| 长沙市| 开原市| 蕉岭县| 合阳县| 靖安县| 邵阳县| 钟山县|