gpt4 book ai didi

python - 如何将 Python 对象转换为 Cython 扩展类型的 std::vector 并返回?

转载 作者:行者123 更新时间:2023-11-30 04:43:36 27 4
gpt4 key购买 nike

我使用 Cython 来包装 C++ 代码。该代码包含定义为的函数:

std::vector<ClassOut> analyze(std::vector<ClassIn> inputVec);

ClassIn 和 ClassOut 是扩展类型。在 Python 中,我希望能够使用列表或 numpy 数组(任何可能且最明智的)调用此函数。我还希望能够访问和修改扩展类型,所以像这样:

运行.py

from cythonCode.classIn import PyClassIn
from cythonCode.classOut import PyClassOut
from cythonCode.analyze import PyAnalyze

classIn_list = []
classIn_list.append(PyClassIn())
classIn_list.append(PyClassIn())
classOut_list = PyAnalyze(classIn_list)
print(classOut_list)

包装器 PyClassIn 和 PyClassOut 工作正常。问题只是从一开始就包装了分析函数。我的包装 PyAnalyze 版本可以在下面找到:

分析.pxd

from libcpp.vector cimport vector
from classOut cimport ClassOut
from classIn cimport ClassIn, PyClassIn

cdef extern from "../cppCode/analyze.h":
vector[ClassOut] analyze(vector[ClassIn])

分析.pyx

def PyAnalyze(vector<PyClassIn> inputVec)
return analyze(inputVec)

analyze.pyx 肯定有错误。我收到错误:

Python object type 'PyClassIn' cannot be used as a template argument

return 语句也必须不正确。 Cython 提示:

Cannot convert 'vector[ClassOut]' to Python object

我在 https://github.com/zyzzler/cython-vector-minimal-example.git 有这个代码作为最小示例

编辑:感谢您的输入,我现在可以包装定义的返回类型,但还不能包装参数。第一条评论中的链接提供了有关获取正确返回类型的重要信息。所以假设我想包装一个定义为的函数:

std::vector<ClassOut> analyze(std::vector<float> inputVec);

一切正常!但是,我必须处理扩展类型 ClassIn 来代替 float 。下面是我现在的代码:

分析.pyx

def PyAnalyze(classesIn):
cdef vector[ClassOut] classesOut = analyze(classesIn)

retval = PyClassOutVector()
retval.move_from(move(classesOut))

return retval

上面的代码抛出错误:

Cannot convert Python object to 'vector[ClassIn]'

这个错误的原因很明确。 “classesIn”是 PyClassIn 对象的 Python 列表,但 analyze(...) 将 vector[ClassIn] 作为输入。所以问题是如何从 Python 列表转换为 std::vector 和/或从 PyClassIn 转换为 ClassIn?我也尝试使用右值引用和移动构造函数形式,但它没有用。我也尝试通过这样的功能来做到这一点:

cdef vector[ClassIn] list_to_vec(classInList):
cdef vector[ClassIn] classInVec
for classIn in classInList:
classInVec.push_back(<ClassIn>classIn)
return classInVec

这里的问题是 <ClassIn>classIn陈述。它说:

no matching function for call to 'ClassIn::ClassIn(PyObject*&)'

所以我在这里真的很疑惑。这怎么能解决?我用上面发布的 git 中的最小示例修改了代码。

EDIT2:为下面的评论提供更多信息。我现在有一个包装 PyClassInVectorPyClassOutVector 的完全一样,见下文:

cdef class PyClassInVector:
cdef vector[ClassIn] vec

cdef move_from(self, vector[ClassIn]&& move_this):
self.vec = move(move_this)

def __getitem__(self, idx):
return PyClassIn2(self, idx)

def __len__(self):
return self.vec.size()

cdef class PyClassIn2:
cdef ClassIn* thisptr
cdef PyClassInVector vector

def __cinit__(self, PyClassInVector vec, idx):
self.vector = vec
self.thisptr = &vec.vec[idx]

analyze.pxd我还补充说:

cdef extern from "<utility>":
vector[ClassIn]&& move(vector[ClassIn]&&)

现在根据评论,在 PyAnalyze我会做的功能:

def PyAnalyze(classesIn):
# classesIn is a list of PyClassIn objects and needs to be converted to a PyClassInVector
classInVec = PyClassInVector()
cdef vector[ClassOut] classesOut = analyze(classInVec.vec)

retval = PyClassOutVector()
retval.move_from(move(classesOut))

return retval

但是正如代码中的注释所说,我如何才能将 PyClassIn 对象 (classesIn) 的列表放入 PyClassInVector (classInVec) 中?

EDIT3:想象一下 PyClassOut用可以通过构造函数设置的属性装饰:

cdef class PyClassOut()
def __cinit__(self, number):
self.classOut_c = ClassOut(number)

@property
def number(self):
return self.classOut_c.number

run.py我正在做这样的事情:

from cythonCode.classIn import PyClassIn
from cythonCode.classOut import PyClassOut
from cythonCode.analyze import PyAnalyze

classIn_list = []
classIn_list.append(PyClassIn(1))
classIn_list.append(PyClassIn(2))

classOut_list = PyAnalyze(classIn_list)

print(classOut_list[0].number)
print(classOut_list[1].number)

classOut_list本质上是 retvalue来自 PyAnalyze功能。重设值是 PyClassOutVector目的。所以classOut_list[0]给我 PyClassOut2索引 0 处的对象。但在这里我无权访问属性 number .我还注意到 classOut_list[1] 的地址与classOut_list[0]中的一个相同.我不明白这一点。我不完全确定“移动”是做什么的。此外,我实际上想要再次拥有一个 python 列表作为 retvalue , 最好是 PyClassOut对象而不是 PyClassOut2对象。那有意义吗?可行吗?

最佳答案

在评论中,我试图推荐一种涉及包装 C++ vector 的解决方案。我更喜欢这种方法,因为它避免了多次复制内存,但我认为它会造成更多的困惑,你宁愿只使用 Python 列表。对不起。

要使用 Python 列表,您只需在 PyAnalyze 中复制输入和输出。您必须手动执行 - 不存在自动转换。您还必须了解包装类和底层 C++ 类之间的区别。您只能将 C++ 类发送到 C++,而不是包装的类。

处理输入很简单:

 def PyAnalyze(classesIn):
# classesIn is a list of PyClassIn objects and needs to be converted to a PyClassInVector
cdef vector[ClassIn] vecIn
cdef vector[ClassOut] vecOut
cdef PyClassIn a
for a in classesIn:
# need to type a to access its C attributes
# Cython should check that a is of the correct type
vecIn.push_back(a.classIn_c)

vecOut = analyze(vecIn)

将数据返回到 Cython 包装为 PyClassOut 有点困难,因为您不能将 C++ 类型发送到 Cython 构造函数(构造函数的所有参数必须是 Python 类型)。只需构建一个空的 PyClassOut,然后将新数据复制到其中。同样,逐个元素地处理 vector

 def PyAnalyze(classesIn):
cdef PyClassOut out_val
# ... use code above ...
out_list = []
for i in range(vecOut.size()):
out_val = PyClassOut()
out_val.classOut_c = vecOut[i]
out_list.append(out_val)
return out_list

关于python - 如何将 Python 对象转换为 Cython 扩展类型的 std::vector 并返回?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58171611/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com