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 Pyrex 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 Pyrex 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 Pyrex 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 Pyrex 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, Pyrex 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 Pyrex 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, Pyrex 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 Pyrex 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, Pyrex generates a call to PyErr_Occurred if 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 Pyrex 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 Pyrex 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 Pyrex 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 Pyrex module accessible to another. However, note that some of these uses have been superseded by the facilities described in Sharing Declarations Between Pyrex Modules, and it is expected that use of the include statement for this purpose will be phased out altogether in future versions.
Python functions can have keyword-only arguments listed after the * parameter and before the ** paramter if any, e.g.
def f(a, b, *args, c, d = 42, e, **kwds):Here c, d and e cannot be passed as position arguments and must be passed as keyword arguments. Furthermore, c and e are required keyword arguments, since they do not have a default value.
...
def g(a, b, *, c, d):takes exactly two positional parameters and has two required keyword parameters.
...
You can also use public declarations to make C functions and variables defined in a Pyrex 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 Pyrex 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 Pyrex 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 Pyrex declarations match the style used in the header file, so that Pyrex can emit the right sort of references to the type in the code it generates. To make this possible, Pyrex 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 Pyrex 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 Pyrex code simply
as Foo, not struct Foo.
C code | Possibilities for corresponding Pyrex code | Comments | |
1 | struct Foo { ... }; |
cdef struct Foo: ... |
Pyrex will refer to the type as struct Foo in the generated C code. |
2 | typedef struct { ... } Foo; |
ctypedef struct Foo: ... |
Pyrex 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 Pyrex (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, Py_ssize_t len)
Pyrex predefines the name Py_ssize_t for use with Python/C API routines. To make your extensions compatible with 64-bit systems, you should always use this type where it is specified in the documentation of Python/C API routines.
The __stdcall and __cdecl calling convention specifiers can be used in Pyrex, with the same syntax as used by C compilers on Windows, for example,
cdef extern int __stdcall FrobnicateWindow(long handle)If __stdcall is used, the function is only considered compatible with other __stdcall functions of the same signature.
cdef void (__stdcall *callback)(void *)
Pyrex 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 Pyrex modules.
The other way is to use a c name specification to give different Pyrex 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 Pyrex 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 Pyrex keywords. For example, if you want to call an external function called print, you can rename it to something else in your Pyrex 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 struct Bunny: # public type declarationIf there are any public declarations in a Pyrex module, a header file called modulename.h file is generated containing equivalent C declarations for inclusion in other C code.
int vorpalness
cdef public int spam # public variable declarationcdef public void grail(Bunny *): # public function declaration
...
The other way of making functions available to C code is by declaring them with the api keyword. A header file called "modulename_api.h" is produced containing declarations of the functions, and a function called import_modulename().
C code wanting to use the functions needs to include the header and call the import_modulename() function. The other functions can then be called as usual.
Any public type declarations in the Pyrex module are also made available when you include modulename_api.h.
delorean.pyx | marty.c |
cdef public struct Vehicle: | #include "delorean_api.h" |
cdef public api void belt_and_braces():However, note that you should include either modulename.h or modulename_api.h in a given C file, not both, otherwise you may get conflicting dual definitions.
...
The above restrictions will most likely remain, since removing them would be difficult and they're not really needed for Pyrex'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 Pyrex.
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 Pyrex doesn't optimize them away, and won't even accept them in places where executable statements are not allowed.
will not work in Pyrex. 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)