2

I found this interesting question on SO to combine multiple decorators in python to a single decorator.

I wanted to do the same thing in Cython. Typically, I have Cython codes that look like:

@cython.boundscheck(False)
@cython.wraparound(False)
@cython.cdivision(True)
cdef ar[dtype_t, ndim=2] sma_vec(ar[dtype_t, ndim=2] x, int m):
    cdef int n
    cdef Py_ssize_t i, j
    ...

or like

@cython.boundscheck(False)
@cython.wraparound(False)
@cython.cdivision(True)
cpdef ar[dtype_t, ndim=2] sma_vec(ar[dtype_t, ndim=2] x, int m):
    cdef int n
    cdef Py_ssize_t i, j
    ...

and I tend to repeat these three decorators @cython.boundscheck(False), @cython.wraparound(False), @cython.cdivision(True) pretty much everywhere.

The solution for regular Python given in that page is

def composed(*decs):
    def deco(f):
        for dec in reversed(decs):
            f = dec(f)
        return f
    return deco

For Cython, I tried to do the following:

cdef composed_for_cdef(*decs):
     cdef deco(f):
          for dec in reversed(decs):
              f = dec(f)
           return f
      return deco

and

cpdef composed_for_cpdef(*decs):
     cpdef deco(f):
          for dec in reversed(decs):
              f = dec(f)
           return f
      return deco

but I got an error during compilation:

cdef composed_for_cdef(*decs):
    cdef deco(f):
               ^
------------------------------------------------------------

stat\movavg.pyx:12:16: C function definition not allowed here

I even tried the solution for regular Python (given above), but I got an error:

@composed(cython.boundscheck(False), cython.wraparound(False), cython.cdivision(True))
^
------------------------------------------------------------

stat\movavg.pyx:24:0: Cdef functions/classes cannot take arbitrary decorators.
Community
  • 1
  • 1
uday
  • 6,453
  • 13
  • 56
  • 94
  • 1
    Considering how Cython's decorators interact with the compiler, I don't think what you're trying to do is possible. It'd be like trying to put all your `__future__` imports in one module and `import *` to turn on future statements. – user2357112 May 22 '15 at 22:56
  • Do the cython decorators actually return a new function object, or augment the argument then return it? – Eric May 22 '15 at 23:22
  • @Eric, not sure I understand what you asked. – uday May 22 '15 at 23:34

1 Answers1

2

Combining decorators is not the optimal apporach here. Simply, add,

# cython: boundscheck=False
# cython: cdivision=True
# cython: wraparound=False

in the header of your source file (see Cython compiler directives), and these options will be applied to all the defined function. Appropriate decorators can then be used to overwrite this default behavior, if necessary.

As to the combined decorator issue, it looks like this is, for the moment, not supported in Cython. For instance, even with a mostly python code,

cpdef composed_for_cpdef(*decs):
   def deco(f):
       for dec in reversed(decs):
           f = dec(f)
       return f
   return deco

I get an error at compilation closures inside cpdef functions not yet supported with Cython 0.22.

rth
  • 10,680
  • 7
  • 53
  • 77