From: Robert Bradshaw Date: Sun, 25 Jan 2009 07:09:36 +0000 (-0800) Subject: Moving sections around X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=729e88c19ec3d8f8d36e986a463bcfb10e897805;p=cython.git Moving sections around --- diff --git a/docs/language_basics.rst b/docs/language_basics.rst index aae6be3f..d641bc0f 100644 --- a/docs/language_basics.rst +++ b/docs/language_basics.rst @@ -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