【问题标题】:Cython: How to use templates?Cython:如何使用模板?
【发布时间】:2016-09-02 02:15:31
【问题描述】:

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

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 实现应该如何?

感谢您的帮助。

【问题讨论】:

    标签: python cython


    【解决方案1】:

    问题 1 - 很遗憾,您不能在那里使用融合类型。 (请参阅之前关于该主题的问题:c++ class in fused typeCython: templates in python class wrappers)。您必须为每个不同的变体创建一个单独的包装器。例如:

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

    不幸的是,这涉及到很多不可避免的代码重复。

    问题 2. if 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
    

    请注意,您需要将 Box (cdef extern from ...) 告诉 Cython,即使您随后没有将其暴露给 Python。

    【讨论】:

    • 非常感谢您。我能够使用您描述的方法使其工作。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-22
    • 2015-06-16
    • 1970-01-01
    • 2021-01-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多