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

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.

主站蜘蛛池模板: 大宁县| 奉化市| 延安市| 五指山市| 湖南省| 姜堰市| 昌吉市| 祁东县| 扎赉特旗| 安顺市| 包头市| 盈江县| 济南市| 葫芦岛市| 会昌县| 佛坪县| 桃源县| 浙江省| 淮阳县| 平罗县| 闵行区| 两当县| 正蓝旗| 古丈县| 裕民县| 深水埗区| 伊春市| 铅山县| 贵溪市| 桂阳县| 开化县| 甘肃省| 弥勒县| 阳江市| 广丰县| 睢宁县| 晋江市| 洛宁县| 安远县| 岳普湖县| 特克斯县|