2016-09-16 26 views
4

我一直在用Cython玩弄最近和應用裝飾的用Cython功能如何裝飾適用於用Cython cpdef功能

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)將memoize的所述fib(5)調用的結果,但它會 memoize的遞歸調用(即fib(4), fib(3), fib(2), fib(1)

作爲@DavidW指出的,cdef, cpdef功能完全在編譯時決定的;裝飾是一個運行時的東西,並不會更新實際的功能。

+0

只是對我的訣竅的快速評論:請注意,我使用了不同的名稱。如果你命名'cdef'函數'_fib',做了'fib = memorize(_fib)',並確保你遞歸調用'fib'(不是'_fib'),我認爲它可以工作,但是你會添加很多每次調用時Python的開銷。 – DavidW

回答

3

- 您不能輕易地爲cdef函數編寫裝飾器。裝飾器cdef功能採取的是諸如cython.boundscheck這些控制Cython代碼生成而不是用戶生成的函數。

一個cdef功能和def功能之間的主要區別在於一個cdef函數具有C接口,而一個def函數變成一個Python可調用,以便可以從Python中使用(但調用它是略小於有效,因爲參數有通過PyObjects傳遞)。 [的兩者內部的cdefdef功能由Python的編譯,以便唯一性能差異來自調用開銷]

通常使用一個修飾的是把一個任意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... 

的第一個問題是,克被翻譯成C代碼等int g(double x, double y)其可以通過一個函數指針來表示,但不作爲任意Python可調用,如plus_one所期望的。其次,wrapper無法知道(從C函數指針)什麼g的參數被稱爲(不能做**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 

因爲g是你已經失去使用功能cdef的整體效益現在是一個通用的Python,可以調用所有的開銷。


附錄:另一種說法是裝飾器是一個運行時Python功能(通常在模塊導入時運行)。 cdef函數是一個編譯時C函數。儘管實現像「編譯時裝飾器」這樣的東西可能不是不可能的,但這對Cython來說是一個非常重要的改變。

+0

明白了。感謝您的解釋。 – Stephen