如何在cython中的函数参数中键入函数
How to type a function in function argument in cython
我在 python 中创建了一个优化函数(暂且称之为 optimizer
)。它需要将函数作为函数参数之一进行优化(我们称之为 objective
)。 objective
是一个接受一维 np.ndarray
和 return 一个 float
数字的函数(这与 C++ 中的 double
相同?)。
我已阅读此 post,但我不确定它是否真的与我的问题相同,当我使用 ctypedef int (*f_type)(int, str)
时,但我收到错误 Cannot convert 'f_type' to Python object
在编译期间。它只适用于 C 函数吗?如何输入 python 函数?
编辑:我的代码是这样的:
cpdef optimizer(objective, int num_particle, int dim,
np.ndarray[double, ndim=1] lower_bound,
np.ndarray[double, ndim=1] upper_bound):
cdef double min_value
cdef np.ndarray[double, ndim=2] positions = np.empty((num_particle,dim), dtype=np.double)
cdef np.ndarray[double, ndim=1] fitness = np.empty(num_particle, dtype=np.double)
cdef int i, j
# do lots of stuff not shown here
# involve the following code:
for i in range(num_particle):
fitness[i] = objective(positions[i])
return min_value
我想知道是否可以键入 objective
以使代码 运行 更快。
我收到错误消息
Cannot convert Python object argument to type 'f_type'
我认为这比您声称得到的更有意义 - 您正在尝试将 Python 对象传递到函数中。请确保您报告的错误消息是您的代码实际生成的错误消息。您对 objective
采用的类型的描述也不符合您显示的代码。
但是,一般来说:不,你不能给你的 objective 函数一个类型说明符来加速它。通用 Python 可调用函数携带的信息比 C 函数指针多得多(例如引用计数、任何闭包捕获变量的详细信息等)。
一种可能的替代方法是从具有适当 cdef
函数的 cdef class
继承,这样您至少可以在特定情况下获得适当的性能:
# an abstract function pointer class
cdef class FPtr:
cdef double function(self,double[:] x) except? 0.0:
# I'm assuming you might want to pass exceptions back to Python - use 0.0 to indicate that there might have been an error
raise NotImplementedError()
# an example class that inherits from the abstract pointer type
cdef class SumSq(FPtr):
cdef double function(self,double[:] x) except? 0.0:
cdef double sum=0.0
for i in range(x.shape[0]):
sum += x[i]**2
return sum
# an example class that just wraps a Python callable
# this will be no faster, but makes the code generically usable
cdef class PyFPtr(FPtr):
cdef object f
def __init__(self,f):
self.f = f
cdef double function(self,double[:] x) except? 0.0:
return self.f(x) # will raise an exception if the types don't match
def example_function(FPtr my_callable):
import numpy as np
return my_callable.function(np.ones((10,)))
使用这个 example_function(SumSq())
可以按预期工作(并且具有 Cython 速度); example_function(PyFPtr(lambda x: x[0]))
按预期工作(可调用中没有 Cython 速度); example_function(PyFPtr(lambda x: "hello"))
给出了预期的类型错误。
我在 python 中创建了一个优化函数(暂且称之为 optimizer
)。它需要将函数作为函数参数之一进行优化(我们称之为 objective
)。 objective
是一个接受一维 np.ndarray
和 return 一个 float
数字的函数(这与 C++ 中的 double
相同?)。
我已阅读此 post,但我不确定它是否真的与我的问题相同,当我使用 ctypedef int (*f_type)(int, str)
时,但我收到错误 Cannot convert 'f_type' to Python object
在编译期间。它只适用于 C 函数吗?如何输入 python 函数?
编辑:我的代码是这样的:
cpdef optimizer(objective, int num_particle, int dim,
np.ndarray[double, ndim=1] lower_bound,
np.ndarray[double, ndim=1] upper_bound):
cdef double min_value
cdef np.ndarray[double, ndim=2] positions = np.empty((num_particle,dim), dtype=np.double)
cdef np.ndarray[double, ndim=1] fitness = np.empty(num_particle, dtype=np.double)
cdef int i, j
# do lots of stuff not shown here
# involve the following code:
for i in range(num_particle):
fitness[i] = objective(positions[i])
return min_value
我想知道是否可以键入 objective
以使代码 运行 更快。
我收到错误消息
Cannot convert Python object argument to type 'f_type'
我认为这比您声称得到的更有意义 - 您正在尝试将 Python 对象传递到函数中。请确保您报告的错误消息是您的代码实际生成的错误消息。您对 objective
采用的类型的描述也不符合您显示的代码。
但是,一般来说:不,你不能给你的 objective 函数一个类型说明符来加速它。通用 Python 可调用函数携带的信息比 C 函数指针多得多(例如引用计数、任何闭包捕获变量的详细信息等)。
一种可能的替代方法是从具有适当 cdef
函数的 cdef class
继承,这样您至少可以在特定情况下获得适当的性能:
# an abstract function pointer class
cdef class FPtr:
cdef double function(self,double[:] x) except? 0.0:
# I'm assuming you might want to pass exceptions back to Python - use 0.0 to indicate that there might have been an error
raise NotImplementedError()
# an example class that inherits from the abstract pointer type
cdef class SumSq(FPtr):
cdef double function(self,double[:] x) except? 0.0:
cdef double sum=0.0
for i in range(x.shape[0]):
sum += x[i]**2
return sum
# an example class that just wraps a Python callable
# this will be no faster, but makes the code generically usable
cdef class PyFPtr(FPtr):
cdef object f
def __init__(self,f):
self.f = f
cdef double function(self,double[:] x) except? 0.0:
return self.f(x) # will raise an exception if the types don't match
def example_function(FPtr my_callable):
import numpy as np
return my_callable.function(np.ones((10,)))
使用这个 example_function(SumSq())
可以按预期工作(并且具有 Cython 速度); example_function(PyFPtr(lambda x: x[0]))
按预期工作(可调用中没有 Cython 速度); example_function(PyFPtr(lambda x: "hello"))
给出了预期的类型错误。