如何用Cython包装返回类类型的C++ Vec3类方法?
问题:Cython包装C++ Vec3类的cross方法报错解决
问题背景
我有一个简单的C++ Vec3类,但在使用Cython包装其cross方法时遇到了报错。相关文件如下:
vec3.h
#ifndef VEC3_H #define VEC3_H struct Vec3 { float x, y, z; Vec3(float x, float y, float z); Vec3 cross(Vec3 other); }; #endif
vec3.cpp
#include "vec3.h" Vec3::Vec3(float x, float y, float z) { this->x = x; this->y = y; this->z = z; } Vec3 Vec3::cross(Vec3 other) { return Vec3(y * other.z - z * other.y, z * other.x - x * other.z, x * other.y - y * other.x); }
vec3.pyx
# cython: language_level=3 # distutils: language=c++ cdef extern from "vec3.h": cdef cppclass Vec3: float x, y, z Vec3(float x, float y, float z) except + Vec3 cross(Vec3 other) cdef class py_Vec3: cdef Vec3 *thisptr def __cinit__(self, x, y, z): self.thisptr = new Vec3(x, y, z) # ... cpdef cross(self, Vec3 other): return self.thisptr.cross(other)
编译步骤
我先编译C++代码:
g++ -c vec3.cpp -o vec3.o ar rcs vec3.a vec3.o
然后运行setup.py:
from distutils.core import setup from distutils.extension import Extension from Cython.Build import cythonize vec3= Extension( name="vec3", sources=["vec3.pyx"], libraries=["linalg"], language="c++" ) setup(name="vec3-test", ext_modules=cythonize([vec3]))
报错信息
运行后cross方法出现如下报错:
Cannot convert 'Vec3f' to Python object
解决方案
问题出在参数类型不匹配、返回值无法转换、链接库配置错误三个点,逐一修正:
1. 修改vec3.pyx
需要让cross方法接受Python层面的py_Vec3对象,将C++返回的Vec3包装成py_Vec3实例返回,同时添加内存释放逻辑:
# cython: language_level=3 # distutils: language=c++ cdef extern from "vec3.h": cdef cppclass Vec3: float x, y, z Vec3(float x, float y, float z) except + Vec3 cross(Vec3 other) cdef class py_Vec3: cdef Vec3 *thisptr def __cinit__(self, x, y, z): self.thisptr = new Vec3(x, y, z) def __dealloc__(self): # 释放内存避免泄漏 del self.thisptr cpdef py_Vec3 cross(self, py_Vec3 other): # 取出内部C++实例调用cross,再包装为py_Vec3返回 cdef Vec3 result = self.thisptr->cross(*other.thisptr) return py_Vec3(result.x, result.y, result.z) # 添加属性访问,方便Python层操作x/y/z property x: def __get__(self): return self.thisptr.x def __set__(self, value): self.thisptr.x = value property y: def __get__(self): return self.thisptr.y def __set__(self, value): self.thisptr.y = value property z: def __get__(self): return self.thisptr.z def __set__(self, value): self.thisptr.z = value
2. 修改setup.py
修正链接库名称和路径,确保能找到编译好的静态库:
from distutils.core import setup from distutils.extension import Extension from Cython.Build import cythonize vec3_ext = Extension( name="vec3", sources=["vec3.pyx"], libraries=["vec3"], # 对应编译出的libvec3.a library_dirs=["."], # 指定库所在目录(当前目录) language="c++" ) setup(name="vec3-test", ext_modules=cythonize([vec3_ext]))
3. 重新编译
按规范生成静态库,再编译Cython扩展:
# 重新生成符合命名规范的静态库 g++ -c vec3.cpp -o vec3.o ar rcs libvec3.a vec3.o # 编译Cython扩展 python setup.py build_ext --inplace
测试使用
修改完成后即可在Python中正常调用:
import vec3 v1 = vec3.py_Vec3(1, 0, 0) v2 = vec3.py_Vec3(0, 1, 0) v3 = v1.cross(v2) print(v3.x, v3.y, v3.z) # 输出:0 0 1
内容的提问来源于stack exchange,提问作者Blackgaurd
相关产品推荐
相关产品推荐

