如何将装饰器应用于Cython cpdef函数

发布于 2021-01-29 15:21:59

我最近一直在使用Cython,在将装饰器应用于Cython函数时遇到了此错误

Cdef functions/classes cannot take arbitrary decorators

这是我修改过的代码:

import functools

def memoize(f):
    computed = {}
    @functools.wraps(f)
    def memoized_f(main_arg, *args, **kwargs):
        if computed.get(main_arg):
            return computed[main_arg]
        computed[main_arg] = f(main_arg, *args, **kwargs)
        return computed[main_arg]
    return memoized_f

@memoize
cpdef int fib(int n):
    return 1 if n < 2 else fib(n - 1) + fib(n - 2)

该错误表明cdef函数只能使用 某些 装饰器。是否可以编写自己的装饰器以应用于cdef函数?


编辑:对于未来的读者:

g = plus_one(_g)绝招@ DavidW的答复中提到 排序的 作品。它不适用于递归。例如,fib = memoize(fib)在我的示例代码中执行的操作不会记住对fib的递归调用,尽管它确实会记住顶级调用。也就是说,调用fib(5)会记住调用的结果fib(5),但
不会 记住递归调用(即fib(4), fib(3), fib(2), fib(1)

正如@DavidW指出的那样,cdef, cpdef函数是在编译时完全确定的。装饰是运行时的东西,不会更新实际功能。

关注者
0
被浏览
138
1 个回答
  • 面试哥
    面试哥 2021-01-29
    为面试而生,有面试问题,就找面试哥。


    ,您无法轻松编写cdef函数的装饰器。装饰器cdef函数需要cython.boundscheck控制Cython代码生成而不是用户生成的函数。

    cdef函数与def函数之间的主要区别在于,cdef函数具有C接口,而def函数变为可调用的Python,因此可以从Python使用(但调用它的效率稍低,因为必须根据PyObjects传递参数)
    。[ a和函数的内部 都是 由Python编译的,因此唯一的性能差异来自调用开销]cdef``def

    装饰器的通常用法是采用任意可调用的Python并对其进行一些修改。例如

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

    现在尝试在cdef函数上使用它

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

    第一个问题是g被转换为C代码,就像int g(double x, double y)可以通过函数指针表示的那样,但是却不能像plus_one预期的那样被任意Python调用。其次,wrapper没有办法(从C函数指针知道)什么g叫s参数(不能做**kwargs),也没有任何简单的方法来进行*args扩展。

    您可以通过采用特定的函数指针类型并返回可调用的Python来制作类似装饰器的内容:

    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
    

    但是, 您已经失去了使用cdef函数的全部好处,因为g现在它是一个可调用的通用Python,带有所有随之而来的开销。


    附录:一种替代的表达方式是装饰器是运行时的Python功能(通常在模块导入时运行)。cdef函数是编译时的C功能。尽管可能并非不可能实现“编译时装饰器”之类的东西,但对Cython来说将是一个相当重大的改变。



知识点
面圈网VIP题库

面圈网VIP题库全新上线,海量真题题库资源。 90大类考试,超10万份考试真题开放下载啦

去下载看看