Sharing Declarations Between Pyrex Modules
This section describes a new set of facilities introduced in Pyrex 0.8
for making C declarations and extension types in one Pyrex module available
for use in another Pyrex module. These facilities are closely modelled
on the Python import mechanism, and can be thought of as a compile-time
version of it.
Contents
Definition and Implementation files
A Pyrex module can be split into two parts: a definition file with
a .pxd suffix, containing C declarations that are to be available
to other Pyrex modules, and an implementation file with a .pyx
suffix, containing everything else. When a module wants to use something
declared in another module's definition file, it imports it using the cimport
statement.
What a Definition File contains
A definition file can contain:
-
Any kind of C type declaration.
-
extern C function or variable declarations.
-
The definition part of an extension type (see
below).
It cannot currently contain any non-extern C function or variable declarations
(although this may be possible in a future version).
It cannot contain the implementations of any C or Python functions,
or any Python class definitions, or any executable statements.
NOTE: You don't need to (and shouldn't) declare anything in
a declaration file public in order to make it available to other
Pyrex modules; its mere presence in a definition file does that. You only
need a public declaration if you want to make something available to external
C code.
What an Implementation File contains
An implementation file can contain any kind of Pyrex statement, although
there are some restrictions on the implementation part of an extension
type if the corresponding definition file also defines that type (see below).
The cimport statement
The cimport statement is used in a definition or implementation
file to gain access to names declared in another definition file. Its syntax
exactly parallels that of the normal Python import statement:
cimport module [, module...]
from module cimport name
[as name] [, name [as name]
...]
Here is an example. The file on the left is a definition file which exports
a C data type. The file on the right is an implementation file which imports
and uses it.
dishes.pxd |
restaurant.pyx |
cdef enum otherstuff:
sausage, eggs, lettuce
cdef struct spamdish:
int oz_of_spam
otherstuff filler |
cimport dishes
from dishes cimport spamdish
cdef void prepare(spamdish *d):
d.oz_of_spam = 42
d.filler = dishes.sausage
def serve():
spamdish d
prepare(&d)
print "%d oz spam, filler no. %d" % \
(d->oz_of_spam,
d->otherstuff) |
It is important to understand that the cimport statement can
only
be used to import C data types, external C functions and variables, and
extension types. It cannot be used to import any Python objects, and (with
one exception) it doesn't imply any Python import at run time. If you want
to refer to any Python names from a module that you have cimported, you
will have to include a regular import statement for it as well.
The exception is that when you use cimport to import an extension
type, its type object is imported at run time and made available by the
name under which you imported it. Using cimport to import extension
types is covered in more detail below.
Search paths for definition files
When you cimport a module called modulename, the Pyrex
compiler searches for a file called modulename.pxd along the search
path for include files, as specified by -I command line options.
Also, whenever you compile a file modulename.pyx, the corresponding
definition file modulename.pxd is first searched for along the
same path, and if found, it is processed before processing the .pyx
file.
Using cimport to resolve naming
conflicts
The cimport mechanism provides a clean and simple way to solve the problem
of wrapping external C functions with Python functions of the same name.
All you need to do is put the extern C declarations into a .pxd file for
an imaginary module, and cimport that module. You can then refer to the
C functions by qualifying them with the name of the module. Here's an example:
c_lunch.pxd |
lunch.pyx |
cdef extern from "lunch.h":
void eject_tomato(float) |
cimport c_lunch
def eject_tomato(float speed):
c_lunch.eject_tomato(speed) |
You don't need any c_lunch.pyx file, because the only things
defined in c_lunch.pxd are extern C entities. There won't be any
actual c_lunch module at run time, but that doesn't matter --
c_lunch
has done its job of providing an additional namespace at compile time.
Sharing Extension Types
An extension type declaration can also be split into two parts, one in
a definition file and the other in the corresponding implementation file.
When this is done, the definition part of the extension type can only contain
C attribute declarations, not methods, and it must contain all of
that type's C attributes. The implementation part may contain methods,
but not any C attributes.
Here is an example of a module which defines and exports an extension
type, and another module which uses it.
Shrubbing.pxd |
Shrubbing.pyx |
cdef class Shrubbery:
cdef int width
cdef int length |
cdef class Shrubbery:
def __new__(self, int w, int l):
self.width = w
self.length = l
def standard_shrubbery():
return Shrubbery(3, 7) |
Landscaping.pyx |
cimport Shrubbing
import Shrubbing
cdef Shrubbing.Shrubbery sh
sh = Shrubbing.standard_shrubbery()
print "Shrubbery size is %d x %d" % (sh.width, sh.height)
|
Some things to note about this example:
-
There is a cdef class shrubbery declaration in both Shrubbing.pxd
and Shrubbing.pyx. When the Shrubbing module is compiled, these two declarations
are combined into one.
-
In Landscaping.pyx, the cimport Shrubbery declaration allows us
to refer to the Shrubbery type as Shrubbing.Shrubbery. But it
doesn't bind the name Shrubbery in Landscaping's module namespace
at run time, so to access Shrubbery.standard_shrubbery we also
need to import Shrubbing.
Back to the Language Overview