Cython:如何使用模板?

时间:2016-05-06 21:56:10

标签: python cython

我想对以下模板化的C ++类进行cython化:

template <typname T>
class Fc2Par
{
public:
  Fc2Par(std::string const& par_file)
  ~Fc2Par()
  std::vector<Box<T>> convert_boxes(std::vector<Box<T>> const& boxes) const;
  std::vector<Point<T>> convert_points(std::vector<Point<T>> const& points) const;
private:
  PartitionMap<T>  par_map;
  PartitionRTree<T> par_idx;
};

实际上,T只会是[int,double]。 Box / Point是附加的模板类,但我不确定是否要在python中公开它。为了进行cythonize,我有以下内容,但我在某些方面陷入困境。我想我可以使用融合型T?

cimport cython
from libcpp.vector cimport vector
from libcpp.string cimport string

my_fused_type = cython.fused_type(cython.int, cython.double)

cdef extern from 'Fc2Par.h':
  cdef cppclass Fc2Par[T]
    Fc2Par(string&) except +
    vector[Box[T]] convert_boxes(vector[Box[T]]&)
    vector[Point[T]] convert_points(vector[Point[T]]&)

cdef class PyFc2Par:
  cdef Fc2Par* thisptr <-- should this be Fc2Par[my_fused_type]*?

  def __cinit__(self, par_file):
    self.thisptr = new Fc2Par[my_fused_type](par_file)
  def __dealloc__(self)
    del self.thisptr
  def convert_boxes(self, boxes)

    I'm not sure what to do here?

  def convert_points(self, points)

    This will be very similar to convert_boxes once I figure that out.

理想情况下,我想在python中使用这样的API:

boxes_int = [(0,0,1,1), (0,0,2,2), ...]
boxes_float = [(0.0,0.0,1.0,1.0), (0.0,0.0,2.0,2.0), ...]

fc2par = PyFc2Par('foo.csv')
converted_int = fc2par.convert_boxes(boxes_int)
converted_float = fc2par.convert_boxes(boxes_float)

它们返回带有xmin,xmax,ymin,ymax的元组列表。

我的问题:

  1. 在这种情况下使用融合类型是否正确?

  2. 如果我列出元组列表,如何在Cython代码中将它们转换为Box [T] / Point [T]而不在Python中公开这些类?获得结果后,我可以将其转换回元组列表并将其发回。即,convert_boxes实现应该如何?

  3. 感谢您的帮助。

1 个答案:

答案 0 :(得分:0)

问题1 - 遗憾的是,您无法在那里使用融合类型。 (请参阅有关此主题的先前问题:c++ class in fused type; Cython: templates in python class wrappers)。您必须为每个不同的变体创建单独的包装器。 e.g:

cdef class PyFc2ParInt:
  cdef Fc2Par[int]* thisptr
  # etc ...

cdef class PyFc2ParDouble:
  cdef Fc2Par[double]* thisptr
  # etc ...

遗憾的是,这涉及到许多不可避免的代码重复。

问题2.如果convert_points实质上涉及迭代Python列表创建框,然后迭代向量以创建Python列表,则实现。粗略的轮廓是:

def convert_points(self, points):
   cdef vector[Box[double]] v # or vector[Box[int]]
   for p in points:
      # I've taken a guess at what the Box constructor looks like
      v.push_back(Box[double](p[0],p[1],p[2],p[3]))

   v = self.thisptr.convert_points(v) # reuse v for the output

   # now iterate through the vector and copy out
   # I've taken a guess at the interface of Box
   output = [ (v[i].left, v[i].right, v[i].top, v[i].bottom)
              for i in range(v.size()) ]
   return output

请注意,您需要告诉Cython关于Boxcdef extern from ...),即使您没有将其公开给Python。