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

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.

主站蜘蛛池模板: 西青区| 霞浦县| 曲阜市| 自治县| 长春市| 华宁县| 固阳县| 昂仁县| 通化县| 大埔县| 永寿县| 甘泉县| 五大连池市| 马公市| 肇源县| 开原市| 穆棱市| 克东县| 光泽县| 盘锦市| 丹阳市| 安达市| 杭州市| 裕民县| 新源县| 安岳县| 绥中县| 酉阳| 蓬安县| 大庆市| 天全县| 缙云县| 扎兰屯市| 姜堰市| 申扎县| 富阳市| 延安市| 信丰县| 冕宁县| 岳普湖县| 五河县|