Commit c41d9a2d authored by Robert Bradshaw's avatar Robert Bradshaw

Merge back in old code as users guide (as it doesn't look like it was all copied over.)

--HG--
rename : index.rst => src/userguide/index.rst
parents b6add9d2 e2458387
......@@ -7,4 +7,5 @@ Welcome to Cython's Documentation
src/quickstart/index
src/tutorial/index
src/userguide/index
src/reference/index
.. highlight:: cython
.. _early-binding-for-speed:
**************************
Early Binding for Speed
**************************
As a dynamic language, Python encourages a programming style of considering
classes and objects in terms of their methods and attributes, more than where
they fit into the class hierarchy.
This can make Python a very relaxed and comfortable language for rapid
development, but with a price - the 'red tape' of managing data types is
dumped onto the interpreter. At run time, the interpreter does a lot of work
searching namespaces, fetching attributes and parsing argument and keyword
tuples. This run-time 'late binding' is a major cause of Python's relative
slowness compared to 'early binding' languages such as C++.
However with Cython it is possible to gain significant speed-ups through the
use of 'early binding' programming techniques.
For example, consider the following (silly) code example:
.. sourcecode:: cython
cdef class Rectangle:
cdef int x0, y0
cdef int x1, y1
def __init__(self, int x0, int y0, int x1, int y1):
self.x0 = x0; self.y0 = y0; self.x1 = x1; self.y1 = y1
def area(self):
area = (self.x1 - self.x0) * (self.y1 - self.y0)
if area < 0:
area = -area
return area
def rectArea(x0, y0, x1, y1):
rect = Rectangle(x0, y0, x1, y1)
return rect.area()
In the :func:`rectArea` method, the call to :meth:`rect.area` and the
:meth:`.area` method contain a lot of Python overhead.
However, in Cython, it is possible to eliminate a lot of this overhead in cases
where calls occur within Cython code. For example:
.. sourcecode:: cython
cdef class Rectangle:
cdef int x0, y0
cdef int x1, y1
def __init__(self, int x0, int y0, int x1, int y1):
self.x0 = x0; self.y0 = y0; self.x1 = x1; self.y1 = y1
cdef int _area(self):
int area
area = (self.x1 - self.x0) * (self.y1 - self.y0)
if area < 0:
area = -area
return area
def area(self):
return self._area()
def rectArea(x0, y0, x1, y1):
cdef Rectangle rect
rect = Rectangle(x0, y0, x1, y1)
return rect._area()
Here, in the Rectangle extension class, we have defined two different area
calculation methods, the efficient :meth:`_area` C method, and the
Python-callable :meth:`area` method which serves as a thin wrapper around
:meth:`_area`. Note also in the function :func:`rectArea` how we 'early bind'
by declaring the local variable ``rect`` which is explicitly given the type
Rectangle. By using this declaration, instead of just dynamically assigning to
``rect``, we gain the ability to access the much more efficient C-callable
:meth:`_rect` method.
But Cython offers us more simplicity again, by allowing us to declare
dual-access methods - methods that can be efficiently called at C level, but
can also be accessed from pure Python code at the cost of the Python access
overheads. Consider this code:
.. sourcecode:: cython
cdef class Rectangle:
cdef int x0, y0
cdef int x1, y1
def __init__(self, int x0, int y0, int x1, int y1):
self.x0 = x0; self.y0 = y0; self.x1 = x1; self.y1 = y1
cpdef int area(self):
int area
area = (self.x1 - self.x0) * (self.y1 - self.y0)
if area < 0:
area = -area
return area
def rectArea(x0, y0, x1, y1):
cdef Rectangle rect
rect = Rectangle(x0, y0, x1, y1)
return rect.area()
.. note::
in earlier versions of Cython, the :keyword:`cpdef` keyword is
:keyword:`rdef` - but has the same effect).
Here, we just have a single area method, declared as :keyword:`cpdef` to make it
efficiently callable as a C function, but still accessible from pure Python
(or late-binding Cython) code.
If within Cython code, we have a variable already 'early-bound' (ie, declared
explicitly as type Rectangle, (or cast to type Rectangle), then invoking its
area method will use the efficient C code path and skip the Python overhead.
But if in Pyrex or regular Python code we have a regular object variable
storing a Rectangle object, then invoking the area method will require:
* an attribute lookup for the area method
* packing a tuple for arguments and a dict for keywords (both empty in this case)
* using the Python API to call the method
and within the area method itself:
* parsing the tuple and keywords
* executing the calculation code
* converting the result to a python object and returning it
So within Cython, it is possible to achieve massive optimisations by
using strong typing in declaration and casting of variables. For tight loops
which use method calls, and where these methods are pure C, the difference can
be huge.
This diff is collapsed.
This diff is collapsed.
Cython Users Guide
==================
Contents:
.. toctree::
:maxdepth: 2
overview
tutorial
language_basics
extension_types
special_methods
sharing_declarations
external_C_code
source_files_and_compilation
wrapping_CPlusPlus
numpy_tutorial
profiling_tutorial
limitations
pyrex_differences
early_binding_for_speed
Indices and tables
------------------
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
.. toctree::
This diff is collapsed.
.. highlight:: cython
.. _cython-limitations:
*************
Limitations
*************
Unsupported Python Features
============================
One of our goals is to make Cython as compatible as possible with standard
Python. This page lists the things that work in Python but not in Cython.
.. TODO: this limitation seems to be removed
.. ::
.. from module import *
.. This relies on at-runtime insertion of objects into the current namespace and
.. probably will be one of the few features never implemented (as any
.. implementation would be very slow). However, there is the --pre-import option
.. with treats all un-declared names as coming from the specified module, which
.. has the same effect as putting "from module import *" at the top-level of the
.. code. Note: the one difference is that builtins cannot be overriden in this
.. way, as the 'pre-import' scope is even higher than the builtin scope.
Nested def statements
----------------------
Function definitions (whether using ``def`` or ``cdef``) cannot be nested within
other function definitions. ::
def make_func():
def f(x):
return x*x
return f
(work in progress) This relies on functional closures
Generators
-----------
Using the yield keywords. (work in progress) This relies on functional closures
.. TODO Not really a limitation, rather an enchancement proposal
.. Support for builtin types
.. --------------------------
.. Support for statically declaring types such as list and dict and sequence
.. should be provided, and optimized code produced.
.. This needs to be well thought-out, and I think Pyrex has some plans along
.. these lines as well.
Other Current Limitations
==========================
* The :func:`globals` and :func:`locals` functions cannot be used.
* Class and function definitions cannot be placed inside control structures.
Semantic differences between Python and Cython
----------------------------------------------
Behaviour of class scopes
^^^^^^^^^^^^^^^^^^^^^^^^^
In Python, referring to a method of a class inside the class definition, i.e.
while the class is being defined, yields a plain function object, but in
Cython it yields an unbound method [#]_. A consequence of this is that the
usual idiom for using the :func:`classmethod` and :func:`staticmethod` functions,
e.g.::
class Spam:
def method(cls):
...
method = classmethod(method)
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.::
def Spam_method(cls):
...
class Spam:
method = classmethod(Spam_method)
.. rubric:: Footnotes
.. [#] The reason for the different behaviour of class scopes is that
Cython-defined Python functions are ``PyCFunction`` objects, not
``PyFunction`` objects, and are not recognised by the machinery that creates a
bound or unbound method when a function is extracted from a class. To get
around this, Cython wraps each method in an unbound method object itself
before storing it in the class's dictionary.
This diff is collapsed.
.. highlight:: cython
.. _overview:
********
Overview
********
About Cython
==============
Cython is a language that makes writing C extensions for the Python language
as easy as Python itself. Cython is based on the well-known `Pyrex
<http://www.cosc.canterbury.ac.nz/greg.ewing/python/Pyrex/>`_ language by Greg Ewing,
but supports more cutting edge functionality and optimizations [#]_.
The Cython language is very close to the Python language, but Cython
additionally supports calling C functions and declaring C types on variables
and class attributes. This allows the compiler to generate very efficient C
code from Cython code.
This makes Cython the ideal language for wrapping external C libraries,
and for fast C modules that speed up the execution of Python code.
Future Plans
============
Cython is not finished. Substantial tasks remaining. See
:ref:`cython-limitations` for a current list.
.. rubric:: Footnotes
.. [#] For differences with Pyrex see :ref:`pyrex-differences`.
This diff is collapsed.
I think this is a result of a recent change to Pyrex that
has been merged into Cython.
If a directory contains an :file:`__init__.py` or :file:`__init__.pyx` file,
it's now assumed to be a package directory. So, for example,
if you have a directory structure::
foo/
__init__.py
shrubbing.pxd
shrubbing.pyx
then the shrubbing module is assumed to belong to a package
called 'foo', and its fully qualified module name is
'foo.shrubbing'.
So when Pyrex wants to find out whether there is a `.pxd` file for shrubbing,
it looks for one corresponding to a module called :module:`foo.shrubbing`. It
does this by searching the include path for a top-level package directory
called 'foo' containing a file called 'shrubbing.pxd'.
However, if foo is the current directory you're running
the compiler from, and you haven't added foo to the
include path using a -I option, then it won't be on
the include path, and the `.pxd` won't be found.
What to do about this depends on whether you really
intend the module to reside in a package.
If you intend shrubbing to be a top-level module, you
will have to move it somewhere else where there is
no :file:`__init__.*` file.
If you do intend it to reside in a package, then there
are two alternatives:
1. cd to the directory containing foo and compile
from there::
cd ..; cython foo/shrubbing.pyx
2. arrange for the directory containing foo to be
passed as a -I option, e.g.::
cython -I .. shrubbing.pyx
Arguably this behaviour is not very desirable, and I'll
see if I can do something about it.
This diff is collapsed.
.. highlight:: cython
.. _sharing-declarations:
********************************************
Sharing Declarations Between Cython Modules
********************************************
This section describes a new set of facilities for making C declarations,
functions and extension types in one Cython module available for use in
another Cython module. These facilities are closely modelled on the Python
import mechanism, and can be thought of as a compile-time version of it.
Definition and Implementation files
====================================
A Cython module can be split into two parts: a definition file with a ``.pxd``
suffix, containing C declarations that are to be available to other Cython
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 :keyword:`cimport`
statement.
A ``.pxd`` file that consists solely of extern declarations does not need
to correspond to an actual ``.pyx`` file or Python module. This can make it a
convenient place to put common declarations, for example declarations of
functions from an :ref:`external library <external-C-code>` that one wants to use in several modules.
What a Definition File contains
================================
A definition file can contain:
* Any kind of C type declaration.
* extern C function or variable declarations.
* Declarations of C functions defined in the module.
* The definition part of an extension type (see below).
It cannot contain any non-extern C variable declarations.
It cannot contain the implementations of any C or Python functions, or any
Python class definitions, or any executable statements. It is needed when one
wants to access :keyword:`cdef` attributes and methods, or to inherit from
:keyword:`cdef` classes defined in this module.
.. note::
You don't need to (and shouldn't) declare anything in a declaration file
public in order to make it available to other Cython 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 Cython 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).
If one doesn't need to :keyword:`cimport` anything from this module, then this
is the only file one needs.
The cimport statement
=======================
The :keyword:`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.
:file:`dishes.pxd`::
cdef enum otherstuff:
sausage, eggs, lettuce
cdef struct spamdish:
int oz_of_spam
otherstuff filler
:file:`restaurant.pyx`::
cimport dishes
from dishes cimport spamdish
cdef void prepare(spamdish *d):
d.oz_of_spam = 42
d.filler = dishes.sausage
def serve():
cdef spamdish d
prepare(&d)
print "%d oz spam, filler no. %d" % (d.oz_of_spam, d.otherstuff)
It is important to understand that the :keyword:`cimport` statement can only
be used to import C data types, 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 :keyword:`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 :keyword:`cimport` to import extension types is covered in more
detail below.
If a ``.pxd`` file changes, any modules that :keyword:`cimport` from it may need to be
recompiled.
Search paths for definition files
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
When you :keyword:`cimport` a module called ``modulename``, the Cython
compiler searches for a file called :file:`modulename.pxd` along the search
path for include files, as specified by ``-I`` command line options.
Also, whenever you compile a file :file:`modulename.pyx`, the corresponding
definition file :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 :keyword:`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 :keyword:`cimport` that module. You can then
refer to the C functions by qualifying them with the name of the module.
Here's an example:
:file:`c_lunch.pxd` ::
cdef extern from "lunch.h":
void eject_tomato(float)
:file:`lunch.pyx` ::
cimport c_lunch
def eject_tomato(float speed):
c_lunch.eject_tomato(speed)
You don't need any :file:`c_lunch.pyx` file, because the only things defined
in :file:`c_lunch.pxd` are extern C entities. There won't be any actual
``c_lunch`` module at run time, but that doesn't matter; the
:file:`c_lunch.pxd` file has done its job of providing an additional namespace
at compile time.
Sharing C Functions
===================
C functions defined at the top level of a module can be made available via
:keyword:`cimport` by putting headers for them in the ``.pxd`` file, for
example,:
:file:`volume.pxd`::
cdef float cube(float)
:file:`spammery.pyx`::
from volume cimport cube
def menu(description, size):
print description, ":", cube(size), \
"cubic metres of spam"
menu("Entree", 1)
menu("Main course", 3)
menu("Dessert", 2)
:file:`volume.pyx`::
cdef float cube(float x):
return x * x * x
.. note::
When a module exports a C function in this way, an object appears in the
module dictionary under the function's name. However, you can't make use of
this object from Python, nor can you use it from Cython using a normal import
statement; you have to use :keyword:`cimport`.
Sharing Extension Types
=======================
An extension type can be made available via :keyword:`cimport` by splitting
its definition into two parts, one in a definition file and the other in the
corresponding implementation file.
The definition part of the extension type can only declare C attributes and C
methods, not Python methods, and it must declare all of that type's C
attributes and C methods.
The implementation part must implement all of the C methods declared in the
definition part, and may not add any further C attributes. It may also define
Python methods.
Here is an example of a module which defines and exports an extension type,
and another module which uses it.::
# Shrubbing.pxd
cdef class Shrubbery:
cdef int width
cdef int length
# Shrubbing.pyx
cdef class Shrubbery:
def __cinit__(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 :keyword:`cdef` class Shrubbery declaration in both
:file:`Shrubbing.pxd` and :file:`Shrubbing.pyx`. When the Shrubbing module
is compiled, these two declarations are combined into one.
* In Landscaping.pyx, the :keyword:`cimport` Shrubbing declaration allows us
to refer to the Shrubbery type as :class:`Shrubbing.Shrubbery`. But it
doesn't bind the name Shrubbing in Landscaping's module namespace at run
time, so to access :func:`Shrubbing.standard_shrubbery` we also need to
``import Shrubbing``.
.. highlight:: cython
.. _compilation:
****************************
Source Files and Compilation
****************************
Cython source file names consist of the name of the module followed by a
``.pyx`` extension, for example a module called primes would have a source
file named :file:`primes.pyx`.
Once you have written your ``.pyx`` file, there are a couple of ways of turning it
into an extension module. One way is to compile it manually with the Cython
compiler, e.g.:
.. sourcecode:: text
$ cython primes.pyx
This will produce a file called :file:`primes.c`, which then needs to be
compiled with the C compiler using whatever options are appropriate on your
platform for generating an extension module. For these options look at the
official Python documentation.
The other, and probably better, way is to use the :mod:`distutils` extension
provided with Cython. The benifit of this method is that it will give the
platform specific compilation options, acting like a stripped down autotools.
Basic setup.py
===============
The distutils extension provided with Cython allows you to pass ``.pyx`` files
directly to the ``Extension`` constructor in your setup file.
If you have a single Cython file that you want to turn into a compiled
extension, say with filename :file:`example.pyx` the associated :file:`setup.py`
would be::
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
setup(
cmdclass = {'build_ext': build_ext},
ext_modules = [Extension("example", ["example.pyx"])]
)
To understand the :file:`setup.py` more fully look at the official
:mod:`distutils` documentation. To compile the extension for use in the
current directory use:
.. sourcecode:: text
$ python setup.py build_ext --inplace
Cython Files Depending on C Files
===================================
When you have come C files that have been wrapped with cython and you want to
compile them into your extension the basic :file:`setup.py` file to do this
would be::
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
sourcefiles = ['example.pyx', 'helper.c', 'another_helper.c']
setup(
cmdclass = {'build_ext': build_ext},
ext_modules = [Extension("example", sourcefiles)]
)
Notice that the files have been given a name, this is not necessary, but it
makes the file easier to format if the list gets long.
The :class:`Extension` class takes many options, and a fuller explanation can
be found in the `distutils documentation`_. Some useful options to know about
are ``include_dirs``, ``libraries``, and ``library_dirs`` which specify where
to find the ``.h`` and library files when linking to external libraries.
.. _distutils documentation: http://docs.python.org/extending/building.html
Multiple Cython Files in a Package
===================================
TODO
Distributing Cython modules
============================
It is strongly recommended that you distribute the generated ``.c`` files as well
as your Cython sources, so that users can install your module without needing
to have Cython available.
It is also recommended that Cython compilation not be enabled by default in the
version you distribute. Even if the user has Cython installed, he probably
doesn't want to use it just to install your module. Also, the version he has
may not be the same one you used, and may not compile your sources correctly.
This simply means that the :file:`setup.py` file that you ship with will just
be a normal distutils file on the generated `.c` files, for the basic example
we would have instead::
from distutils.core import setup
from distutils.extension import Extension
setup(
ext_modules = [Extension("example", ["example.c"])]
)
.. _pyximport:
Pyximport
===========
.. TODO add some text about how this is Paul Prescods code. Also change the
tone to be more universal (i.e. remove all the I statements)
Cython is a compiler. Therefore it is natural that people tend to go
through an edit/compile/test cycle with Cython modules. But my personal
opinion is that one of the deep insights in Python's implementation is
that a language can be compiled (Python modules are compiled to ``.pyc``)
files and hide that compilation process from the end-user so that they
do not have to worry about it. Pyximport does this for Cython modules.
For instance if you write a Cython module called :file:`foo.pyx`, with
Pyximport you can import it in a regular Python module like this::
import pyximport; pyximport.install()
import foo
Doing so will result in the compilation of :file:`foo.pyx` (with appropriate
exceptions if it has an error in it).
If you would always like to import Cython files without building them
specially, you can also the first line above to your :file:`sitecustomize.py`.
That will install the hook every time you run Python. Then you can use
Cython modules just with simple import statements. I like to test my
Cython modules like this:
.. sourcecode:: text
$ python -c "import foo"
Dependency Handling
--------------------
In Pyximport 1.1 it is possible to declare that your module depends on
multiple files, (likely ``.h`` and ``.pxd`` files). If your Cython module is
named ``foo`` and thus has the filename :file:`foo.pyx` then you should make
another file in the same directory called :file:`foo.pyxdep`. The
:file:`modname.pyxdep` file can be a list of filenames or "globs" (like
``*.pxd`` or ``include/*.h``). Each filename or glob must be on a separate
line. Pyximport will check the file date for each of those files before
deciding whether to rebuild the module. In order to keep track of the
fact that the dependency has been handled, Pyximport updates the
modification time of your ".pyx" source file. Future versions may do
something more sophisticated like informing distutils of the
dependencies directly.
Limitations
------------
Pyximport does not give you any control over how your Cython file is
compiled. Usually the defaults are fine. You might run into problems if
you wanted to write your program in half-C, half-Cython and build them
into a single library. Pyximport 1.2 will probably do this.
Pyximport does not hide the Distutils/GCC warnings and errors generated
by the import process. Arguably this will give you better feedback if
something went wrong and why. And if nothing went wrong it will give you
the warm fuzzy that pyximport really did rebuild your module as it was
supposed to.
For further thought and discussion
------------------------------------
I don't think that Python's :func:`reload` will do anything for changed
``.so``'s on some (all?) platforms. It would require some (easy)
experimentation that I haven't gotten around to. But reload is rarely used in
applications outside of the Python interactive interpreter and certainly not
used much for C extension modules. Info about Windows
`<http://mail.python.org/pipermail/python-list/2001-July/053798.html>`_
``setup.py install`` does not modify :file:`sitecustomize.py` for you. Should it?
Modifying Python's "standard interpreter" behaviour may be more than
most people expect of a package they install..
Pyximport puts your ``.c`` file beside your ``.pyx`` file (analogous to
``.pyc`` beside ``.py``). But it puts the platform-specific binary in a
build directory as per normal for Distutils. If I could wave a magic
wand and get Cython or distutils or whoever to put the build directory I
might do it but not necessarily: having it at the top level is *VERY*
*HELPFUL* for debugging Cython problems.
This diff is collapsed.
.. highlight:: cython
.. _tutorial:
*********
Tutorial
*********
The Basics of Cython
====================
The fundamental nature of Cython can be summed up as follows: Cython is Python
with C data types.
Cython is Python: Almost any piece of Python code is also valid Cython code.
(There are a few :ref:`cython-limitations`, but this approximation will
serve for now.) The Cython compiler will convert it into C code which makes
equivalent calls to the Python/C API.
But Cython is much more than that, because parameters and variables can be
declared to have C data types. Code which manipulates Python values and C
values can be freely intermixed, with conversions occurring automatically
wherever possible. Reference count maintenance and error checking of Python
operations is also automatic, and the full power of Python's exception
handling facilities, including the try-except and try-finally statements, is
available to you -- even in the midst of manipulating C data.
Cython Hello World
===================
As Cython can accept almost any valid python source file, one of the hardest
things in getting started is just figuring out how to compile your extension.
So lets start with the canonical python hello world::
print "Hello World"
So the first thing to do is rename the file to :file:`helloworld.pyx`. Now we
need to make the :file:`setup.py`, which is like a python Makefile (for more
information see :ref:`compilation`). Your :file:`setup.py` should look like::
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
setup(
cmdclass = {'build_ext': build_ext},
ext_modules = [Extension("helloworld", ["helloworld.pyx"])]
)
To use this to build your Cython file use the commandline options:
.. sourcecode:: text
$ python setup.py build_ext --inplace
Which will leave a file in your local directory called :file:`helloworld.so` in unix
or :file:`helloworld.dll` in Windows. Now to use this file: start the python
interpreter and simply import it as if it was a regular python module::
>>> import helloworld
Hello World
Congratulations! You now know how to build a Cython extension. But So Far
this example doesn't really give a feeling why one would ever want to use Cython, so
lets create a more realistic example.
:mod:`pyximport`: Cython Compilation the Easy Way
==================================================
If your module doesn't require any extra C libraries or a special
build setup, then you can use the pyximport module by Paul Prescod and
Stefan Behnel to load .pyx files directly on import, without having to
write a :file:`setup.py` file. It is shipped and installed with
Cython and can be used like this::
>>> import pyximport; pyximport.install()
>>> import helloworld
Hello World
Since Cython 0.11, the :mod:`pyximport` module also has experimental
compilation support for normal Python modules. This allows you to
automatically run Cython on every .pyx and .py module that Python
imports, including the standard library and installed packages.
Cython will still fail to compile a lot of Python modules, in which
case the import mechanism will fall back to loading the Python source
modules instead. The .py import mechanism is installed like this::
>>> pyximport.install(pyimport = True)
Fibonacci Fun
==============
From the official Python tutorial a simple fibonacci function is defined as:
.. literalinclude:: ../examples/tutorial/fib1/fib.pyx
Now following the steps for the Hello World example we first rename the file
to have a `.pyx` extension, lets say :file:`fib.pyx`, then we create the
:file:`setup.py` file. Using the file created for the Hello World example, all
that you need to change is the name of the Cython filename, and the resulting
module name, doing this we have:
.. literalinclude:: ../examples/tutorial/fib1/setup.py
Build the extension with the same command used for the helloworld.pyx:
.. sourcecode:: text
$ python setup.py build_ext --inplace
And use the new extension with::
>>> import fib
>>> fib.fib(2000)
1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597
Primes
=======
Here's a small example showing some of what can be done. It's a routine for
finding prime numbers. You tell it how many primes you want, and it returns
them as a Python list.
:file:`primes.pyx`:
.. literalinclude:: ../examples/tutorial/primes/primes.pyx
:linenos:
You'll see that it starts out just like a normal Python function definition,
except that the parameter ``kmax`` is declared to be of type ``int`` . This
means that the object passed will be converted to a C integer (or a
``TypeError.`` will be raised if it can't be).
Lines 2 and 3 use the ``cdef`` statement to define some local C variables.
Line 4 creates a Python list which will be used to return the result. You'll
notice that this is done exactly the same way it would be in Python. Because
the variable result hasn't been given a type, it is assumed to hold a Python
object.
Lines 7-9 set up for a loop which will test candidate numbers for primeness
until the required number of primes has been found. Lines 11-12, which try
dividing a candidate by all the primes found so far, are of particular
interest. Because no Python objects are referred to, the loop is translated
entirely into C code, and thus runs very fast.
When a prime is found, lines 14-15 add it to the p array for fast access by
the testing loop, and line 16 adds it to the result list. Again, you'll notice
that line 16 looks very much like a Python statement, and in fact it is, with
the twist that the C parameter ``n`` is automatically converted to a Python
object before being passed to the append method. Finally, at line 18, a normal
Python return statement returns the result list.
Compiling primes.pyx with the Cython compiler produces an extension module
which we can try out in the interactive interpreter as follows::
>>> import primes
>>> primes.primes(10)
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
See, it works! And if you're curious about how much work Cython has saved you,
take a look at the C code generated for this module.
Language Details
================
For more about the Cython language, see :ref:`language-basics`.
To dive right in to using Cython in a numerical computation context, see :ref:`numpy_tutorial`.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment