Commit 729e88c1 authored by Robert Bradshaw's avatar Robert Bradshaw

Moving sections around

parent 2a0e8f14
......@@ -6,6 +6,75 @@
Language Basics
*****************
C variable and type definitions
===============================
The :keyword:`cdef` statement is used to declare C variables, either local or
module-level::
cdef int i, j, k
cdef float f, g[42], *h
and C :keyword:`struct`, :keyword:`union` or :keyword:`enum` types::
cdef struct Grail:
int age
float volume
cdef union Food:
char *spam
float *eggs
cdef enum CheeseType:
cheddar, edam,
camembert
cdef enum CheeseState:
hard = 1
soft = 2
runny = 3
There is currently no special syntax for defining a constant, but you can use
an anonymous :keyword:`enum` declaration for this purpose, for example,::
cdef enum:
tons_of_spam = 3
.. note::
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::
cdef Grail *gp
and not::
cdef struct Grail *gp # WRONG
There is also a ``ctypedef`` statement for giving names to types, e.g.::
ctypedef unsigned long ULong
ctypedef int *IntPtr
Grouping multiple C declarations
--------------------------------
If you have a series of declarations that all begin with :keyword:`cdef`, you
can group them into a :keyword:`cdef` block like this::
cdef:
struct Spam:
int tons
int i
float f
Spam *p
void f(Spam *s):
print s.tons, "Tons of spam"
Python functions vs. C functions
==================================
......@@ -75,73 +144,96 @@ object as the explicit return type of a function, e.g.::
In the interests of clarity, it is probably a good idea to always be explicit
about object parameters in C functions.
C variable and type definitions
-------------------------------
The :keyword:`cdef` statement is also used to declare C variables, either local or
module-level::
Error return values
-------------------
cdef int i, j, k
cdef float f, g[42], *h
If you don't do anything special, a function declared with :keyword:`cdef` that
does not return a Python object has no way of reporting Python exceptions to
its caller. If an exception is detected in such a function, a warning message
is printed and the exception is ignored.
and C :keyword:`struct`, :keyword:`union` or :keyword:`enum` types::
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 struct Grail:
int age
float volume
cdef int spam() except -1:
...
cdef union Food:
char *spam
float *eggs
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.
cdef enum CheeseType:
cheddar, edam,
camembert
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 enum CheeseState:
hard = 1
soft = 2
runny = 3
cdef int spam() except? -1:
...
There is currently no special syntax for defining a constant, but you can use
an anonymous :keyword:`enum` declaration for this purpose, for example,::
The "?" indicates that the value ``-1`` only indicates a possible error. In this
case, Cython generates a call to :cfunc:`PyErr_Occurred` if the exception value is
returned, to make sure it really is an error.
cdef enum:
tons_of_spam = 3
There is also a third form of exception value declaration::
.. note::
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::
cdef int spam() except *:
...
cdef Grail *gp
This form causes Cython to generate a call to :cfunc:`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.
Otherwise there is little use for this form.
and not::
An external C++ function that may raise an exception can be declared with::
cdef struct Grail *gp # WRONG
cdef int spam() except +
There is also a ``ctypedef`` statement for giving names to types, e.g.::
See :ref:`wrapping-cplusplus` for more details.
ctypedef unsigned long ULong
Some things to note:
ctypedef int *IntPtr
* Exception values can only declared for functions returning an integer, enum,
float or pointer type, and the value must be a constant expression.
Void functions can only use the ``except *`` form.
* The exception value specification is part of the signature of the function.
If you're passing a pointer to a function as a parameter or assigning it
to a variable, the declared type of the parameter or variable must have
the same exception value specification (or lack thereof). Here is an
example of a pointer-to-function declaration with an exception
value::
Grouping multiple C declarations
--------------------------------
int (*grail)(int, char *) except -1
If you have a series of declarations that all begin with :keyword:`cdef`, you
can group them into a :keyword:`cdef` block like this::
* You don't need to (and shouldn't) declare exception values for functions
which return Python objects. Remember that a function with no declared
return type implicitly returns a Python object. (Exceptions on such functions
are implicitly propagated by returning NULL.)
cdef:
struct Spam:
int tons
Checking return values of non-Cython functions
----------------------------------------------
int i
float f
Spam *p
It's important to understand that the except clause does not cause an error to
be raised when the specified value is returned. For example, you can't write
something like::
cdef extern FILE *fopen(char *filename, char *mode) except NULL # WRONG!
and expect an exception to be automatically raised if a call to :func:`fopen`
returns ``NULL``. The except clause doesn't work that way; its only purpose is
for propagating Python 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 :func:`fopen`, you will have to check the
return value and raise it yourself, for example,::
cdef FILE *p
p = fopen("spam.txt", "r")
if p == NULL:
raise SpamError("Couldn't open the spam file")
void f(Spam *s):
print s.tons, "Tons of spam"
Automatic type conversions
==========================
......@@ -273,6 +365,60 @@ Python variable residing in the scope where it is assigned.
except AttributeError:
True = 1
Built-in Functions
------------------
Cython compiles calls to the following built-in functions into direct calls to
the corresponding Python/C API routines, making them particularly fast.
+------------------------------+-------------+----------------------------+
| Function and arguments | Return type | Python/C API Equivalent |
+==============================+=============+============================+
| abs(obj) | object | PyNumber_Absolute |
+------------------------------+-------------+----------------------------+
| delattr(obj, name) | int | PyObject_DelAttr |
+------------------------------+-------------+----------------------------+
| dir(obj) | object | PyObject_Dir |
| getattr(obj, name) (Note 1) | | |
| getattr3(obj, name, default) | | |
+------------------------------+-------------+----------------------------+
| hasattr(obj, name) | int | PyObject_HasAttr |
+------------------------------+-------------+----------------------------+
| hash(obj) | int | PyObject_Hash |
+------------------------------+-------------+----------------------------+
| intern(obj) | object | PyObject_InternFromString |
+------------------------------+-------------+----------------------------+
| isinstance(obj, type) | int | PyObject_IsInstance |
+------------------------------+-------------+----------------------------+
| issubclass(obj, type) | int | PyObject_IsSubclass |
+------------------------------+-------------+----------------------------+
| iter(obj) | object | PyObject_GetIter |
+------------------------------+-------------+----------------------------+
| len(obj) | Py_ssize_t | PyObject_Length |
+------------------------------+-------------+----------------------------+
| pow(x, y, z) (Note 2) | object | PyNumber_Power |
+------------------------------+-------------+----------------------------+
| reload(obj) | object | PyImport_ReloadModule |
+------------------------------+-------------+----------------------------+
| repr(obj) | object | PyObject_Repr |
+------------------------------+-------------+----------------------------+
| setattr(obj, name) | void | PyObject_SetAttr |
+------------------------------+-------------+----------------------------+
Note 1: There are two different functions corresponding to the Python
:func:`getattr` depending on whether a third argument is used. In a Python
context, they both evaluate to the Python :func:`getattr` function.
Note 2: Only the three-argument form of :func:`pow` is supported. Use the
``**`` operator otherwise.
Only direct function calls using these names are optimised. If you do
something else with one of these names that assumes it's a Python object, such
as assign it to a Python variable, and later call it, the call will be made as
a Python function call.
Operator Precedence
-------------------
......@@ -321,95 +467,6 @@ Like other Python looping statements, break and continue may be used in the
body, and the loop may have an else clause.
Error return values
===================
If you don't do anything special, a function declared with :keyword:`cdef` that
does not return a Python object has no way of reporting Python exceptions to
its caller. If an exception is detected in such a function, a warning message
is printed and the exception is ignored.
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 :cfunc:`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 Cython to generate a call to :cfunc:`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.
Otherwise there is little use for this form.
An external C++ function that may raise an exception can be declared with::
cdef int spam() except +
See :ref:`wrapping-cplusplus` for more details.
Some things to note:
* Exception values can only declared for functions returning an integer, enum,
float or pointer type, and the value must be a constant expression.
Void functions can only use the ``except *`` form.
* The exception value specification is part of the signature of the function.
If you're passing a pointer to a function as a parameter or assigning it
to a variable, the declared type of the parameter or variable must have
the same exception value specification (or lack thereof). Here is an
example of a pointer-to-function declaration with an exception
value::
int (*grail)(int, char *) except -1
* You don't need to (and shouldn't) declare exception values for functions
which return Python objects. Remember that a function with no declared
return type implicitly returns a Python object. (Exceptions on such functions
are implicitly propagated by returning NULL.)
Checking return values of non-Cython functions
----------------------------------------------
It's important to understand that the except clause does not cause an error to
be raised when the specified value is returned. For example, you can't write
something like::
cdef extern FILE *fopen(char *filename, char *mode) except NULL # WRONG!
and expect an exception to be automatically raised if a call to :func:`fopen`
returns ``NULL``. The except clause doesn't work that way; its only purpose is
for propagating Python 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 :func:`fopen`, you will have to check the
return value and raise it yourself, for example,::
cdef FILE *p
p = fopen("spam.txt", "r")
if p == NULL:
raise SpamError("Couldn't open the spam file")
The include statement
=====================
......@@ -456,66 +513,15 @@ extra positional arguments, e.g.::
takes exactly two positional parameters and has two required keyword parameters.
Built-in Functions
------------------
Cython compiles calls to the following built-in functions into direct calls to
the corresponding Python/C API routines, making them particularly fast.
+------------------------------+-------------+----------------------------+
| Function and arguments | Return type | Python/C API Equivalent |
+==============================+=============+============================+
| abs(obj) | object | PyNumber_Absolute |
+------------------------------+-------------+----------------------------+
| delattr(obj, name) | int | PyObject_DelAttr |
+------------------------------+-------------+----------------------------+
| dir(obj) | object | PyObject_Dir |
| getattr(obj, name) (Note 1) | | |
| getattr3(obj, name, default) | | |
+------------------------------+-------------+----------------------------+
| hasattr(obj, name) | int | PyObject_HasAttr |
+------------------------------+-------------+----------------------------+
| hash(obj) | int | PyObject_Hash |
+------------------------------+-------------+----------------------------+
| intern(obj) | object | PyObject_InternFromString |
+------------------------------+-------------+----------------------------+
| isinstance(obj, type) | int | PyObject_IsInstance |
+------------------------------+-------------+----------------------------+
| issubclass(obj, type) | int | PyObject_IsSubclass |
+------------------------------+-------------+----------------------------+
| iter(obj) | object | PyObject_GetIter |
+------------------------------+-------------+----------------------------+
| len(obj) | Py_ssize_t | PyObject_Length |
+------------------------------+-------------+----------------------------+
| pow(x, y, z) (Note 2) | object | PyNumber_Power |
+------------------------------+-------------+----------------------------+
| reload(obj) | object | PyImport_ReloadModule |
+------------------------------+-------------+----------------------------+
| repr(obj) | object | PyObject_Repr |
+------------------------------+-------------+----------------------------+
| setattr(obj, name) | void | PyObject_SetAttr |
+------------------------------+-------------+----------------------------+
Note 1: There are two different functions corresponding to the Python
:func:`getattr` depending on whether a third argument is used. In a Python
context, they both evaluate to the Python :func:`getattr` function.
Note 2: Only the three-argument form of :func:`pow` is supported. Use the
``**`` operator otherwise.
Only direct function calls using these names are optimised. If you do
something else with one of these names that assumes it's a Python object, such
as assign it to a Python variable, and later call it, the call will be made as
a Python function call.
Conditional Compilation
-----------------------
=======================
Some features are available for conditional compilation and compile-time
constants within a Cython source file.
Compile-Time Definitions
^^^^^^^^^^^^^^^^^^^^^^^^
------------------------
A compile-time constant can be defined using the DEF statement::
......@@ -552,7 +558,7 @@ expression must evaluate to a Python value of type ``int``, ``long``,
print "I like", FavouriteFood
Conditional Statements
^^^^^^^^^^^^^^^^^^^^^^
----------------------
The ``IF`` statement can be used to conditionally include or exclude sections
of code at compile time. It works in a similar way to the ``#if`` preprocessor
......
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