How to apply decorators to Cython cpdef functions

后端 未结 1 691
迷失自我
迷失自我 2020-12-30 07:47

I\'ve been playing around with Cython lately and I came across this error when applying a decorator to a Cython function

Cdef functions/classes cannot take arb

相关标签:
1条回答
  • 2020-12-30 08:12

    No - you can't easily write decorators for cdef functions. The decorators cdef functions take are things like cython.boundscheck which control the Cython code generation rather than user generated functions.

    The main difference between a cdef function and a def function is that a cdef function has a C interface while a def function becomes a Python callable so can be used from Python (but calling it is slightly less efficient because the arguments have to be passed in terms of PyObjects). [The inside of both a cdef and def function is compiled by Python so the only performance difference comes from the calling overhead]

    The usual use of a decorator is to take an arbitrary Python callable and make some modification to it. For example

    def plus_one(f):
        def wrapper(*args,**kwargs):
           return f(*args,**kwargs) + 1
        return wrapper
    

    now try to use it on a cdef function

    cdef int g(double x, double y):
        # some implementation...
    

    The first problem is that g is translated to C code like int g(double x, double y) which can be represented by a function pointer but not as an arbitrary Python callable like plus_one expects. Second, wrapper has no way of knowing (from a C function pointer) what gs arguments are called (can't do **kwargs) or any easy way of doing the *args expansion.

    You can make something like a decorator by taking a specific function pointer type and returning a Python callable:

    cdef plus_one(int (*f)(double, double):
        def wrapper(double x, double y):
           return f(x, y) + 1
        return wrapper
    
    cdef int _g(double x, double y):
        # some implementation
    
    g = plus_one(_g) # kind of like a decorator
    

    However, you've lost the whole benefit of using a cdef function since g is now a generic Python callable with all the overhead that goes with it.


    Addendum: an alternative way of putting it is that decorators are a runtime Python feature (usually run at module import). cdef functions are a compile-time C feature. While it probably wouldn't be impossible to implement something like "compile-time decorators" it would be a pretty significant change to Cython.

    0 讨论(0)
提交回复
热议问题