Commit 332a5263 authored by scoder's avatar scoder

Merge pull request #210 from nbruin/master

Explain difference between cdef and cpdef
parents e8bd1789 e56d5ec6
...@@ -94,13 +94,16 @@ object or if it is guaranteed that an exception will not be raised ...@@ -94,13 +94,16 @@ object or if it is guaranteed that an exception will not be raised
within the function call. within the function call.
A side-effect of cdef is that the function is no longer available from A side-effect of cdef is that the function is no longer available from
Python-space, as Python wouldn't know how to call it. Using the Python-space, as Python wouldn't know how to call it. It is also no
``cpdef`` keyword instead of cdef, a Python wrapper is also created, longer possible to change ``f` at runtime.
so that the function is available both from Cython (fast, passing
typed values directly) and from Python (wrapping values in Python
objects).
Note also that it is no longer possible to change ``f`` at runtime. Using the ``cpdef`` keyword instead of ``cdef``, a Python wrapper is also
created, so that the function is available both from Cython (fast, passing
typed values directly) and from Python (wrapping values in Python
objects). In fact, ``cpdef`` does not just provide a Python wrapper, it also
installs logic to allow the method to be overridden by python methods, even
when called from within cython. This does add a tiny overhead compared to ``cdef``
methods.
Speedup: 150 times over pure Python. Speedup: 150 times over pure Python.
......
...@@ -32,20 +32,25 @@ Cython code and pure Python code. ...@@ -32,20 +32,25 @@ Cython code and pure Python code.
So far our integration example has not been very useful as it only So far our integration example has not been very useful as it only
integrates a single hard-coded function. In order to remedy this, integrates a single hard-coded function. In order to remedy this,
without sacrificing speed, we will use a cdef class to represent a with hardly sacrificing speed, we will use a cdef class to represent a
function on floating point numbers:: function on floating point numbers::
cdef class Function: cdef class Function:
cpdef double evaluate(self, double x) except *: cpdef double evaluate(self, double x) except *:
return 0 return 0
Like before, cpdef makes two versions of the method available; one The directive cpdef makes two versions of the method available; one
fast for use from Cython and one slower for use from Python. Then:: fast for use from Cython and one slower for use from Python. Then::
cdef class SinOfSquareFunction(Function): cdef class SinOfSquareFunction(Function):
cpdef double evaluate(self, double x) except *: cpdef double evaluate(self, double x) except *:
return sin(x**2) return sin(x**2)
This does slightly more than providing a python wrapper for a cdef
method: unlike a cdef method, a cpdef method is fully overrideable by
subclasses and instance attributes. This adds a little calling overhead
compared to a cdef method.
Using this, we can now change our integration example:: Using this, we can now change our integration example::
def integrate(Function f, double a, double b, int N): def integrate(Function f, double a, double b, int N):
...@@ -62,8 +67,8 @@ Using this, we can now change our integration example:: ...@@ -62,8 +67,8 @@ Using this, we can now change our integration example::
print(integrate(SinOfSquareFunction(), 0, 1, 10000)) print(integrate(SinOfSquareFunction(), 0, 1, 10000))
This is almost as fast as the previous code, however it is much more flexible This is almost as fast as the previous code, however it is much more flexible
as the function to integrate can be changed. It is even possible to pass as the function to integrate can be changed. We can even pass in a new
in a new function defined in Python-space:: function defined in Python-space::
>>> import integrate >>> import integrate
>>> class MyPolynomial(integrate.Function): >>> class MyPolynomial(integrate.Function):
......
...@@ -426,7 +426,10 @@ methods from ``cdef`` to ``cpdef``. This will let Cython generate two ...@@ -426,7 +426,10 @@ methods from ``cdef`` to ``cpdef``. This will let Cython generate two
entry points, one that is callable from normal Python code using the entry points, one that is callable from normal Python code using the
Python call semantics and Python objects as arguments, and one that is Python call semantics and Python objects as arguments, and one that is
callable from C code with fast C semantics and without requiring callable from C code with fast C semantics and without requiring
intermediate argument conversion from or to Python types. intermediate argument conversion from or to Python types. Note that ``cpdef``
methods ensure that they can be appropriately overridden by Python
methods even when they are called from Cython. This adds a tiny overhead
compared to ``cdef`` methods.
The following listing shows the complete implementation that uses The following listing shows the complete implementation that uses
``cpdef`` methods where possible:: ``cpdef`` methods where possible::
......
...@@ -343,7 +343,9 @@ C methods ...@@ -343,7 +343,9 @@ C methods
Extension types can have C methods as well as Python methods. Like C Extension types can have C methods as well as Python methods. Like C
functions, C methods are declared using :keyword:`cdef` or :keyword:`cpdef` instead of functions, C methods are declared using :keyword:`cdef` or :keyword:`cpdef` instead of
:keyword:`def`. C methods are "virtual", and may be overridden in derived :keyword:`def`. C methods are "virtual", and may be overridden in derived
extension types.:: extension types. In addition, :keyword:`cpdef` methods can even be overridden by python
methods when called as C method. This adds a little to their calling overhead
compared to a :keyword:`cdef` methd::
# pets.pyx # pets.pyx
cdef class Parrot: cdef class Parrot:
......
...@@ -100,7 +100,11 @@ interpreted Python code. So, any functions that you want to "export" from your ...@@ -100,7 +100,11 @@ interpreted Python code. So, any functions that you want to "export" from your
Cython module must be declared as Python functions using def. Cython module must be declared as Python functions using def.
There is also a hybrid function, called :keyword:`cpdef`. A :keyword:`cpdef` There is also a hybrid function, called :keyword:`cpdef`. A :keyword:`cpdef`
can be called from anywhere, but uses the faster C calling conventions can be called from anywhere, but uses the faster C calling conventions
when being called from other Cython code. when being called from other Cython code. A :keyword:`cpdef` can also be overridden
by a Python method on a subclass or an instance attribute, even when called from Cython.
If this happens, most performance gains are of course lost and even if it does not,
there is a tiny overhead in calling a :keyword:`cpdef` method from Cython compared to
calling a :keyword:`cdef` method.
Parameters of either type of function can be declared to have C data types, Parameters of either type of function can be declared to have C data types,
using normal C declaration syntax. For example,:: using normal C declaration syntax. For example,::
......
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