Stefan Behnel | 13 Jul 2012 11:31
Picon
Favicon

Re: Inlining functions in .pxd while making them available to non-cython methods?

Joel Burton, 13.07.2012 06:42:
> I have a medium-sized Python project we're evaluating moving critical speed 
> parts to Cython. One of our requirements is that we'll have users who will 
> want/need to run this under vanilla Python, so we've been playing with the 
> "magic" files capabilites of adding declarations in .pxd files that sit 
> aside our vanilla Python files--and with great success so far (and about a 
> 7x speedup in a not-very-math-heavy application).
> 
> We have several functions in a utils.py module that are short and widely 
> used:
> 
> def unneg(self):
>    ... a few lines of bit manipulation
> 
> These are perfect candidates for turning into inline cdef'd functions -- 
> but there doesn't seem to be any way we can see to do that. We can simply 
> reference the module in the .pxd file as:
> 
> cdef inline unsigned char unneg(self)
> 
> and leave the original body in the py. It doesn't look like Cython actually 
> inlines this, though--we see no speed difference at all. If we move the 
> entire definition into the .pxd:
> 
> cdef inline unsigned char unneg(self):
>    ... same lines of bit manipulation

Yes, this is supported as the one way to share inlined functions (and
methods) between different modules.

> we see a good speed increase, as expected. However: then, non-Cython users 
> can no longer see this function.
> 
> Are there are any good workarounds for this? 

My advice would be to write an explicit 'def' function somewhere in the one
module that you want to export the function from, then call the inlined
function from that (i.e. delegate to it). It's common to rename the inlined
function to _unneg (with a leading underscore) in that case, to mark it as
the private or module local function.

If Cython exported cimported names automatically, the function would appear
in all modules in which you cimport the .pxd file, which is most likely not
what you want. It's much better to export it explicitly to the Python API
level. Since it's inlined anyway, it won't make any difference if you call
it from inside a def method or write it into a module literally.

Stefan


Gmane