2017-09-04 6 views
1

cdef 파이썬 스크립트에서 Cython 함수를 다른 파이썬 함수 (예 : def)로 전달할 수 있습니까?파이썬 인터페이스를 통한 cython 함수 전달

최소 예 :

test_module.pyx

cpdef min_arg(f, int N): 
    cdef double x = 100000. 
    cdef int best_i = -1 

    for i in range(N): 
     if f(i) < x: 
      x = f(i) 
      best_i = i 
    return best_i 

def py_f(x): 
    return (x-5)**2 

cdef public api double cy_f(double x): 
    return (x-5)**2 

test.py

import pyximport; pyximport.install() 
import testmodule 

testmodule.min_arg(testmodule.py_f, 100) 

이 잘 작동하지만, 나는 또한

을 할 수 있어야합니다
testmodule.min_arg(testmodule.cy_f, 100) 

을 test.py에서 가져 와서 cython 속도 (각 f(i) 호출에 대한 Python 오버 헤드 없음)를 갖습니다. 그러나 분명히 파이썬은 def이나 cpdef을 선언하지 않았기 때문에 cy_f에 대해 알지 못합니다.

from scipy import LowLevelCallable 
cy_f = LowLevelCallable.from_cython(testmodule, 'cy_f') 
testmodule.min_arg(cy_f, 100) 

을하지만이 TypeError: 'LowLevelCallable' object is not callable을 제공합니다

이 같은 일이 존재 기대했다.

미리 감사드립니다.

답변

1

LowLevelCallable은 기본 Python 모듈에서 수용해야하는 함수 클래스입니다. 이 작품은 같은 scipy.ndimage.generic_filter1d 또는 scipy.integrate.quad로의 사용을 만드는 SciPy 루틴을 통해 scipy.integrate.quad

같은 포장 방법을 사용하려는 경우, 당신도 가야 루틴 직교을 포함하여 몇 가지 모듈 완료되었습니다. 그러나 코드는 컴파일 된 확장자에 있습니다.

귀하의 문제가 콜백에 대해 합리적으로 잘 정의 된 경우이를 직접 구현하는 것입니다. 내가 인터페이스 cyfunc_d_d 정의하는 .pxd 파일에서

  1. : 내 코드 중 하나에 이런 짓을했는지, 그래서 나는 단순함에 대한 링크를 게시 https://github.com/pdebuyl/skl1/blob/master/skl1/core.pxd
  2. 을 나는 "기본이 인터페이스를 사용 다시 수 "cython 모듈 https://github.com/pdebuyl/skl1/blob/master/skl1/euler.pyx 및"사용자 정의 "모듈에도 있습니다.

    1. test_interface.pxd

      : 나는 당신의 문제에 코드를 적용

      사이 썬 수준에서 물체의 통과를 허용하면서

    마지막 코드는 일반 "사이 썬-사이 썬"을 만드는 호출

    cdef class cyfunc:                               
        cpdef double f(self, double x)                           
    
    cdef class pyfunc(cyfunc):                             
        cdef object py_f                              
        cpdef double f(self, double x)                           
    
  3. test_interface.pyx

    cdef class cyfunc: 
        cpdef double f(self, double x): 
         return 0 
        def __cinit__(self): 
         pass 
    
    
    cdef class pyfunc(cyfunc): 
        cpdef double f(self, double x): 
         return self.py_f(x) 
        def __init__(self, f): 
         self.py_f = f 
    
  4. setup.py

    from setuptools import setup, Extension                          
    from Cython.Build import cythonize                           
    
    setup(                                  
        ext_modules=cythonize((Extension('test_interface', ["test_interface.pyx"]),                
              Extension('test_module', ["test_module.pyx"]))                 
            )                              
    )                                   
    
  5. test_module.pyx

    from test_interface cimport cyfunc, pyfunc                         
    
    cpdef min_arg(f, int N):                             
        cdef double x = 100000.                             
        cdef int best_i = -1                             
        cdef int i                                
        cdef double current_value                            
    
        cdef cyfunc py_f                              
    
        if isinstance(f, cyfunc):                            
         py_f = f                               
         print('cyfunc')                              
        elif callable(f):                              
         py_f = pyfunc(f)                             
         print('no cyfunc')                             
        else:                                 
         raise ValueError("f should be a callable or a cyfunc")                    
    
        for i in range(N):                              
         current_value = py_f.f(i)                           
         if current_value < x:                            
          x = current_value                            
          best_i = i                              
        return best_i                               
    
    def py_f(x):                                
        return (x-5)**2                               
    
    cdef class cy_f(cyfunc):                             
        cpdef double f(self, double x):                           
         return (x-5)**2                              
    

사용하려면

python3 setup.py build_ext --inplace 
python3 -c 'import test_module ; print(test_module.min_arg(test_module.cy_f(), 10))' 
python3 -c 'import test_module ; print(test_module.min_arg(test_module.py_f, 10))'