【发布时间】:2017-01-25 05:17:43
【问题描述】:
我最近一直在玩 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 函数?
编辑:对于未来的读者:
@DavidW 的回答中提到的g = plus_one(_g) 技巧有点有效。它不适用于递归。例如在我的示例代码中执行 fib = memoize(fib) 不会记住对 fib 的递归调用,尽管它确实会记住顶级调用。即调用fib(5) 将记住fib(5) 调用的结果,但它不会记住递归调用(即fib(4), fib(3), fib(2), fib(1))
正如@DavidW 指出的,cdef, cpdef 函数在编译时完全确定;装饰是运行时的东西,不会更新实际功能。
【问题讨论】:
-
简单评论一下我的技巧:请注意我使用了不同的名称。如果您将
cdef函数命名为_fib,则使用fib = memorize(_fib)并确保递归调用fib(不是_fib)我认为它会起作用,但是您会在每次调用时增加大量Python 开销.