Python functions are defined using the def statement, as in Python. They take Python objects as parameters and return Python objects.
C functions are defined using the new cdef statement. They take either Python objects or C values as parameters, and can return either Python objects or C values.
Within a Cython module, Python functions and C functions can call each other freely, but only Python functions can be called from outside the module by interpreted Python code. So, any functions that you want to "export" from your Cython module must be declared as Python functions using def.
Parameters of either type of function can be declared to have C data types, using normal C declaration syntax. For example,
When a parameter of a Python function is declared to have a C data type, it is passed in as a Python object and automatically converted to a C value, if possible. Automatic conversion is currently only possible for numeric types and string types; attempting to use any other type for the parameter of a Python function will result in a compile-time error.def spam(int i, char *s):
...cdef int eggs(unsigned long l, float f):
...
C functions, on the other hand, can have parameters of any type, since they're passed in directly using a normal C function call.
Reference counting for these objects is performed automatically according to the standard Python/C API rules (i.e. borrowed references are taken as parameters and a new reference is returned).cdef spamobjs(x, y):
...
The name object can also be used to explicitly declare something as a Python object. This can be useful if the name being declared would otherwise be taken as the name of a type, for example,
declares a parameter called int which is a Python object. You can also use object as the explicit return type of a function, e.g.cdef ftang(object int):
...
In the interests of clarity, it is probably a good idea to always be explicit about object parameters in C functions.cdef object ftang(object int):
...
and C struct, union or enum types:cdef int i, j, k
cdef float f, g[42], *h
There is currently no special syntax for defining a constant, but you can use an anonymous enum declaration for this purpose, for example,cdef struct Grail:
int age
float volumecdef union Food:
char *spam
float *eggscdef enum CheeseType:
cheddar, edam,
camembertcdef enum CheeseState:
hard = 1
soft = 2
runny = 3
cdef enum:Note that the words struct, union and enum are used only when defining a type, not when referring to it. For example, to declare a variable pointing to a Grail you would write
tons_of_spam = 3
and notcdef Grail *gp
There is also a ctypedef statement for giving names to types, e.g.cdef struct Grail *gp # WRONG
ctypedef unsigned long ULongctypedef int *IntPtr
C types |
From Python types |
To Python types |
---|---|---|
[unsigned] char [unsigned] short int, long |
int, long |
int |
unsigned int unsigned long [unsigned] long long |
int, long |
long |
float, double, long double |
int, long, float |
float |
char * |
str |
str |
cdef char *sthen Cython will produce the error message "Obtaining char * from temporary Python value". The reason is that concatenating the two Python strings produces a new Python string object that is referenced only by a temporary internal variable that Cython generates. As soon as the statement has finished, the temporary variable will be decrefed and the Python string deallocated, leaving s dangling. Since this code could not possibly work, Cython refuses to compile it.
s = pystring1 + pystring2
cdef char *sIt is then your responsibility to hold the reference p for as long as necessary.
p = pystring1 + pystring2
s = p
You can use a global statement at the module level to explicitly declare a name to be a module-level name when there would otherwise not be any indication of this, for example,
global __name__Without the global statement, the above would print the name of the builtins module.
print __name__
because, due to the assignment, the True will always be looked up in the module-level scope. You would have to do something like this instead:try:
x = True
except NameError:
True = 1
import __builtin__
try:
True = __builtin__.True
except AttributeError:
True = 1
If Python objects and C values are mixed in an expression, conversions are performed automatically between Python objects and C numeric or string types.
Reference counts are maintained automatically for all Python objects, and all Python operations are automatically checked for errors, with appropriate action taken.
c'X'
cdef char *p, float *qWarning: Don't attempt to use a typecast to convert between Python and C data types -- it won't do the right thing. Leave Cython to perform the conversion automatically.
p = <char*>q
for i in range(n):won't be very fast, even if i and n are declared as C integers, because range is a Python function. For iterating over ranges of integers, Cython has another form of for-loop:
...
for i from 0 <= i < n:If the loop variable and the lower and upper bounds are all C integers, this form of loop will be much faster, because Cython will translate it into pure C code.
...
Some things to note about the for-from loop:
If you want a C function that does not return a Python object to be able to propagate exceptions to its caller, you need to declare an exception value for it. Here is an example:
cdef int spam() except -1:With this declaration, whenever an exception occurs inside spam, it will immediately return with the value -1. Furthermore, whenever a call to spam returns -1, an exception will be assumed to have occurred and will be propagated.
...
When you declare an exception value for a function, you should never explicitly return that value. If all possible return values are legal and you can't reserve one entirely for signalling errors, you can use an alternative form of exception value declaration:
cdef int spam() except? -1:The "?" indicates that the value -1 only indicates a possible error. In this case, Cython generates a call to PyErr_Occurredif the exception value is returned, to make sure it really is an error.
...
There is also a third form of exception value declaration:
cdef int spam() except *:This form causes Cython to generate a call to PyErr_Occurred after every call to spam, regardless of what value it returns. If you have a function returning void that needs to propagate errors, you will have to use this form, since there isn't any return value to test.
...
Some things to note:
int (*grail)(int, char *) except -1
and expect an exception to be automatically raised if a call to fopen returns NULL. The except clause doesn't work that way; its only purpose is for propagating exceptions that have already been raised, either by a Cython function or a C function that calls Python/C API routines. To get an exception from a non-Python-aware function such as fopen, you will have to check the return value and raise it yourself, for example,cdef extern FILE *fopen(char *filename, char *mode) except NULL # WRONG!
cdef FILE *p
p = fopen("spam.txt", "r")
if p == NULL:
raise SpamError("Couldn't open the spam file")
The contents of the named file are textually included at that point. The included file can contain any complete top-level Cython statements, including other include statements. The include statement itself can only appear at the top level of a file.include "spamstuff.pxi"
The include statement can also be used in conjunction with public declarations to make C functions and variables defined in one Cython module accessible to another. However, note that some of these uses have been superseded by the facilities described in Sharing Declarations Between Cython Modules, and it is expected that use of the include statement for this purpose will be phased out altogether in future versions.
You can also use public declarations to make C functions and variables defined in a Cython module available to external C code. The need for this is expected to be less frequent, but you might want to do it, for example, if you are embedding Python in another application as a scripting language. Just as a Cython module can be used as a bridge to allow Python code to call C code, it can also be used to allow C code to call Python code.
cdef extern int spam_countercdef extern void order_spam(int tons)
To achieve this, you can tell Cython that the declarations are to be found in a C header file, like this:
The cdef extern from clause does three things:cdef extern from "spam.h":int spam_countervoid order_spam(int tons)
ctypedef int size_t
cdef extern from *:
...
It's important to make the Cython declarations match the style used in the header file, so that Cython can emit the right sort of references to the type in the code it generates. To make this possible, Cython provides two different syntaxes for declaring a struct, union or enum type. The style introduced above corresponds to the use of a tag name. To get the other style, you prefix the declaration with ctypedef, as illustrated below.
The following table shows the various possible styles that can be found in a header file, and the corresponding Cython declaration that you should put in the cdef exern from block. Struct declarations are used as an example; the same applies equally to union and enum declarations.
Note that in all the cases below, you refer to the type in Cython code simply
as Foo, not struct Foo.
C code | Possibilities for corresponding Cython code | Comments | |
1 | struct Foo { ... }; |
cdef struct Foo: ... |
Cython will refer to the type as struct Foo in the generated C code. |
2 | typedef struct { ... } Foo; |
ctypedef struct Foo: ... |
Cython will refer to the type simply as Foo in the generated C code. |
3 | typedef struct
foo { ... } Foo; |
cdef struct foo: ... ctypedef foo Foo #optional |
If the C header uses both a tag and a typedef with different names, you can use either form of declaration in Cython (although if you need to forward reference the type, you'll have to use the first form). |
ctypedef struct Foo: ... |
|||
4 | typedef struct Foo { ... } Foo; |
cdef struct Foo: ... |
If the header uses the same name for the tag and the typedef, you won't be able to include a ctypedef for it -- but then, it's not necessary. |
will allow you to create Python strings containing null bytes.cdef extern from "Python.h":object PyString_FromStringAndSize(char *s, int len)
Cython 0.8 provides a couple of different ways of solving this problem. The best way, especially if you have many C functions to wrap, is probably to put the extern C function declarations into a different namespace using the facilities described in the section on sharing declarations between Cython modules.
The other way is to use a c name specification to give different Cython and C names to the C function. Suppose, for example, that you want to wrap an external function called eject_tomato. If you declare it as
then its name inside the Cython module will be c_eject_tomato, whereas its name in C will be eject_tomato. You can then wrap it withcdef extern void c_eject_tomato "eject_tomato" (float speed)
so that users of your module can refer to it as eject_tomato.def eject_tomato(speed):
c_eject_tomato(speed)
Another use for this feature is referring to external names that happen to be Cython keywords. For example, if you want to call an external function called print, you can rename it to something else in your Cython module.
As well as functions, C names can be specified for variables, structs, unions, enums, struct and union members, and enum values. For example,
cdef extern int one "ein", two "zwei"cdef enum surprise "inquisition":
cdef extern float three "drei"
cdef struct spam "SPAM":
int i "eye"
first "alpha"
second "beta" = 3
cdef public int spam # public variable declarationIf there are any public declarations in a Cython module, a .h file is generated containing equivalent C declarations for inclusion in other C code.cdef public void grail(int num_nuns): # public function declaration
...
Cython also generates a .pxi file containing Cython versions of the declarations for inclusion in another Cython module using the include statement. If you use this, you will need to arrange for the module using the declarations to be linked against the module defining them, and for both modules to be available to the dynamic linker at run time. I haven't tested this, so I can't say how well it will work on the various platforms.
NOTE: If all you want to export is an extension type, there is now a better way -- see Sharing Declarations Between Cython Modules.
The above restrictions will most likely remain, since removing them would be difficult and they're not really needed for Cython's intended applications.Function definitions (whether using def or cdef) cannot be nested within other function definitions.
Class definitions can only appear at the top level of a module, not inside a function.
The import * form of import is not allowed anywhere (other forms of the import statement are fine, though).
Generators cannot be defined in Cython.
The globals() and locals() functions cannot be used.
There are also some temporary limitations, which may eventually be lifted, including:
Class and function definitions cannot be placed inside control structures.
In-place arithmetic operators (+=, etc) are not yet supported.
List comprehensions are not yet supported.
There is no support for Unicode.
Special methods of extension types cannot have functioning docstrings.
The use of string literals as comments is not recommended at present, because Cython doesn't optimize them away, and won't even accept them in places where executable statements are not allowed.
will not work in Cython. This can be worked around by defining the function outside the class, and then assigning the result of classmethod or staticmethod inside the class, i.e.class Spam:def method(cls):
...method = classmethod(method)
def Spam_method(cls):
...class Spam:method = classmethod(Spam_method)
where grail.h actually containscdef extern from "grail.h":
char *nun
and you doextern const char *nun;
which will cause the C compiler to complain. You can work around it by casting away the constness:cdef void languissement(char *s):
#something that doesn't change s...languissement(nun)
languissement(<char *>nun)