[Pyrex] C versus Python access

Robert Bradshaw robertwb at math.washington.edu
Tue Oct 30 23:45:11 CET 2007


Funny you should ask, there's a new call type in Cython that does  
exactly this. Specifically, if you have

cdef class Rect:

     cdef int width, height

     def __init__(self, int width, int height):
         self.width = width
         self.height = height

     cpdef int area(self):
         return self.width * self.height

It will create a (python-accessible) def function that wraps the  
cpdef function, but if the call is made on a Rect object, e.g.

cdef Rect my_rect = Rect(3,4)
print my_rect.area()

then the fast c method is called. The result is much cleaner code and  
no messy wrapper functions with different names. On top of that it is  
still overrideable, if you have a cdef subclass, override it with a  
cpdef method, and if you (or someone using your code) creates a  
python subclass, they can override it with a normal python method  
(which won't be as fast of course, but will get called even if the  
call is made from pyrex). The overhead is extremely small. This is an  
extremely new functionality and needs to be better documented. (It  
used to be called rdef by the way.)

Also, on a completely separate note, if you're interested in shaving  
off CPU cycles, Cython also generates def methods with the METH_NOARG  
and METH_O type if possible, to avoid overhead with tuple unpacking,  
etc. (One still may have to do a dictionary lookup to call it.)

- Robert



On Oct 30, 2007, at 3:09 PM, David McNab wrote:

> Hi folks,
>
> I'm trying to optimise a pile of Pyrex code, mainly by using C method
> calls wherever possible - but trying to keep the more important  
> methods
> accessible from Python.
>
> To give a simple and very silly example:
>
>         cdef class Rect:
>
>             cdef readonly int width, height
>
>             def __init__(self, int width, int height):
>                 self.width = width
>                 self.height = height
>
>             cdef public int _area(self):
>                 return self.width * self.height
>
>             def area(self):
>                 return self._area()
>
> Here, I've defined a C method '_area', which can be called efficiently
> from Pyrex code without all the argument parsing, getattr, python  
> object
> calls etc. Also, Python method 'area' is a thin wrapper around  
> '_area()'
> which makes '_area()' available to Python callers.
>
> In this approach, I'm trying to get the best of both worlds - methods
> which can be called efficiently at C level, but are also wrapped and
> exposed to Python callers.
>
> Is there a better way to shave off CPU cycles?
>
> Cheers
> David
>
>
>
>
> _______________________________________________
> Pyrex mailing list
> Pyrex at lists.copyleft.no
> http://lists.copyleft.no/mailman/listinfo/pyrex




More information about the Pyrex mailing list