返回对象指针:“无法将 'Coordinate *' 转换为 Python 对象”
Returning Object Pointer: 'Cannot convert 'Coordinate *' to Python object'
我目前正在尝试对我的 c++ classes 进行 cython 化,以便在 python 中使用,我从我的一个简单的 class 开始,但我坚持使用 returning 一个指针。我试图解决这个问题是添加一个复制构造函数并添加到 return Python 版本的 C++ class 但没有任何成功。
我收到以下错误:
Error compiling Cython file:
------------------------------------------------------------
...
def bearing(self, Coordinate *coordinate):
return self.thisptr.bearing(coordinate)
def destination(self, double bearing, double distance):
return PyCCoordinate(self.thisptr.destination(bearing, distance))
^
------------------------------------------------------------
./coordinate.pyx:32:53: Cannot convert 'Coordinate *' to Python object
这是我的文件
coordinate.h
class Coordinate {
private:
double m_x = 0;
double m_y = 0;
public:
Coordinate(const double x, const double y);
Coordinate(const Coordinate *coord);
void setX(const double value);
void setY(const double value);
double getX();
double getY();
double distance(Coordinate *coord);
double bearing(Coordinate *coord);
Coordinate *destination(const double bearing, const double distance);
};
coordinate.cpp
#include <cmath>
#include "coordinate.h"
Coordinate::Coordinate(const double x, const double y) {
m_x = x;
m_y = y;
}
Coordinate::Coordinate(const Coordinate *coord) {
m_x = coord->x;
m_y = coord->y;
}
void Coordinate::setX(const double value) {
m_x = value;
}
void Coordinate::setY(const double value) {
m_y = value;
}
double Coordinate::getX() {
return m_x;
}
double Coordinate::getY() {
return m_y;
}
double Coordinate::distance(Coordinate *coord) {
return sqrt(pow(m_x - coord->getX(), 2.0) + pow(m_y - coord->getY(), 2.0));
}
double Coordinate::bearing(Coordinate *coord) {
const double len_x = coord->getX() - m_x;
const double len_y = coord->getY() - m_y;
double res = atan2(len_y, len_x);
if (res < 0.0) {
res += 2.0 * M_PI;
}
return res;
}
Coordinate *Coordinate::destination(const double bearing, const double distance) {
double new_x = m_x + cos(bearing) * distance;
double new_y = m_y + sin(bearing) * distance;
return new Coordinate(new_x, new_y);
}
coordinate.pxy
cdef extern from "coordinate.h":
cdef cppclass Coordinate:
Coordinate(const double x, const double y) except +
Coordinate(const Coordinate *coord) except +
void setX(const double value)
void setY(const double value)
double getX()
double getY()
double distance(Coordinate *coord)
double bearing(Coordinate *coord)
Coordinate *destination(const double bearing, const double distance)
cdef class PyCCoordinate:
cdef Coordinate *thisptr
def __cinit__(self, double x, double y):
self.thisptr = new Coordinate(x,y)
def __cinit__(self, Coordinate* coord):
self.thisptr = new Coordinate(coord)
def __dealloc__(self):
del self.thisptr
def distance(self, Coordinate *coordinate):
return self.thisptr.distance(coordinate)
def bearing(self, Coordinate *coordinate):
return self.thisptr.bearing(coordinate)
def destination(self, double bearing, double distance):
return PyCCoordinate(self.thisptr.destination(bearing, distance))
一个问题是 cython 语法有点误导:如果 def
-函数被定义为例如(因为你的例子不是最小的我做了一个不相关的):
def twice(double d):
return 2.0*d
然后将参数传递给此 (python) 函数,不是作为 C-double,而是作为通常的 Python-object。然而,早期绑定将导致 cython 尝试在 运行 时间通过 __pyx_PyFloat_AsDouble
将此 Python-object 转换为 C-double 作为调用函数时的第一件事 - 这一切发生在幕后,所以作为编码员,你有这个欺骗性的填充,你会传递一个真正的双精度函数。
但是,这种自动转换仅适用于某些类型 - 最突出的是 double
、int
、cdef
-classes 等。对于其他类型,这是不可能的,例如对于原始指针(这也意味着指向自定义 cpp-classes 的指针)——没有像 __pyx_PyFloat_AsDouble
这样的东西。
例如
def twice(double *d):
pass
无法被 cython 化,因为原始指针无法自动转换 from/to 一个 python-对象,python-函数需要它。
可以用原始指针定义一个 cdef
函数,因为它们不过是简单的 C 函数,因此
cdef twice(double *d):
pass
会编译。但是,这对 __cinit__
没有帮助,因为它必须是 def
函数。
不幸的是,Cython 不会显示您代码中的所有错误,只会显示它找到的第一个错误 - 否则它会告诉您所有带有 Coordinate *coordinate
的 def
都是无效的。
如何求解呢?基本上你应该在签名中使用你的 cdef
-wrapper-class PyCCoordinate
然后 thisptr
- 用于计算,例如:
def distance(self, PyCCoordinate coordinate):
return self.thisptr.distance(coordinate.thisptr)
这个解决方案显然不适用于对象的构造,就像在方法 destination
中一样 - 您必须先构造一个 PyCCoordinate
对象才能使用它!一个可能的解决方案是有一个构造函数,它将构造一个 thisptr
为 NULL
的包装对象,调用它并手动设置此指针,例如
cdef class PyCCoordinate:
cdef Coordinate *thisptr
def __cinit__(self):
pass
def __dealloc__(self):
del self.thisptr
def destination(self, double bearing, double distance):
cdef PyCCoordinate res=PyCCoordinate()
res.thisptr=self.thisptr.destination(bearing, distance)
return res
另一个问题:cython(也是python),不像c++,不知道重载,所以不能定义两个不同的构造函数(也不能定义其中一个为private),所以必须做dispatch手动,例如:
cdef class PyCCoordinate:
cdef Coordinate *thisptr
def __cinit__(self, x=None, y=None):
if x is None or y is None:#default, "private" constructor
pass #thisptr is initialized to NULL
else:
self.thisptr = new Coordinate(x,y) #
def __dealloc__(self):
del self.thisptr
def destination(self, double bearing, double distance):
cdef PyCCoordinate res=PyCCoordinate()
res.thisptr=self.thisptr.destination(bearing, distance)
return res
我目前正在尝试对我的 c++ classes 进行 cython 化,以便在 python 中使用,我从我的一个简单的 class 开始,但我坚持使用 returning 一个指针。我试图解决这个问题是添加一个复制构造函数并添加到 return Python 版本的 C++ class 但没有任何成功。
我收到以下错误:
Error compiling Cython file:
------------------------------------------------------------
...
def bearing(self, Coordinate *coordinate):
return self.thisptr.bearing(coordinate)
def destination(self, double bearing, double distance):
return PyCCoordinate(self.thisptr.destination(bearing, distance))
^
------------------------------------------------------------
./coordinate.pyx:32:53: Cannot convert 'Coordinate *' to Python object
这是我的文件
coordinate.h
class Coordinate {
private:
double m_x = 0;
double m_y = 0;
public:
Coordinate(const double x, const double y);
Coordinate(const Coordinate *coord);
void setX(const double value);
void setY(const double value);
double getX();
double getY();
double distance(Coordinate *coord);
double bearing(Coordinate *coord);
Coordinate *destination(const double bearing, const double distance);
};
coordinate.cpp
#include <cmath>
#include "coordinate.h"
Coordinate::Coordinate(const double x, const double y) {
m_x = x;
m_y = y;
}
Coordinate::Coordinate(const Coordinate *coord) {
m_x = coord->x;
m_y = coord->y;
}
void Coordinate::setX(const double value) {
m_x = value;
}
void Coordinate::setY(const double value) {
m_y = value;
}
double Coordinate::getX() {
return m_x;
}
double Coordinate::getY() {
return m_y;
}
double Coordinate::distance(Coordinate *coord) {
return sqrt(pow(m_x - coord->getX(), 2.0) + pow(m_y - coord->getY(), 2.0));
}
double Coordinate::bearing(Coordinate *coord) {
const double len_x = coord->getX() - m_x;
const double len_y = coord->getY() - m_y;
double res = atan2(len_y, len_x);
if (res < 0.0) {
res += 2.0 * M_PI;
}
return res;
}
Coordinate *Coordinate::destination(const double bearing, const double distance) {
double new_x = m_x + cos(bearing) * distance;
double new_y = m_y + sin(bearing) * distance;
return new Coordinate(new_x, new_y);
}
coordinate.pxy
cdef extern from "coordinate.h":
cdef cppclass Coordinate:
Coordinate(const double x, const double y) except +
Coordinate(const Coordinate *coord) except +
void setX(const double value)
void setY(const double value)
double getX()
double getY()
double distance(Coordinate *coord)
double bearing(Coordinate *coord)
Coordinate *destination(const double bearing, const double distance)
cdef class PyCCoordinate:
cdef Coordinate *thisptr
def __cinit__(self, double x, double y):
self.thisptr = new Coordinate(x,y)
def __cinit__(self, Coordinate* coord):
self.thisptr = new Coordinate(coord)
def __dealloc__(self):
del self.thisptr
def distance(self, Coordinate *coordinate):
return self.thisptr.distance(coordinate)
def bearing(self, Coordinate *coordinate):
return self.thisptr.bearing(coordinate)
def destination(self, double bearing, double distance):
return PyCCoordinate(self.thisptr.destination(bearing, distance))
一个问题是 cython 语法有点误导:如果 def
-函数被定义为例如(因为你的例子不是最小的我做了一个不相关的):
def twice(double d):
return 2.0*d
然后将参数传递给此 (python) 函数,不是作为 C-double,而是作为通常的 Python-object。然而,早期绑定将导致 cython 尝试在 运行 时间通过 __pyx_PyFloat_AsDouble
将此 Python-object 转换为 C-double 作为调用函数时的第一件事 - 这一切发生在幕后,所以作为编码员,你有这个欺骗性的填充,你会传递一个真正的双精度函数。
但是,这种自动转换仅适用于某些类型 - 最突出的是 double
、int
、cdef
-classes 等。对于其他类型,这是不可能的,例如对于原始指针(这也意味着指向自定义 cpp-classes 的指针)——没有像 __pyx_PyFloat_AsDouble
这样的东西。
例如
def twice(double *d):
pass
无法被 cython 化,因为原始指针无法自动转换 from/to 一个 python-对象,python-函数需要它。
可以用原始指针定义一个 cdef
函数,因为它们不过是简单的 C 函数,因此
cdef twice(double *d):
pass
会编译。但是,这对 __cinit__
没有帮助,因为它必须是 def
函数。
不幸的是,Cython 不会显示您代码中的所有错误,只会显示它找到的第一个错误 - 否则它会告诉您所有带有 Coordinate *coordinate
的 def
都是无效的。
如何求解呢?基本上你应该在签名中使用你的 cdef
-wrapper-class PyCCoordinate
然后 thisptr
- 用于计算,例如:
def distance(self, PyCCoordinate coordinate):
return self.thisptr.distance(coordinate.thisptr)
这个解决方案显然不适用于对象的构造,就像在方法 destination
中一样 - 您必须先构造一个 PyCCoordinate
对象才能使用它!一个可能的解决方案是有一个构造函数,它将构造一个 thisptr
为 NULL
的包装对象,调用它并手动设置此指针,例如
cdef class PyCCoordinate:
cdef Coordinate *thisptr
def __cinit__(self):
pass
def __dealloc__(self):
del self.thisptr
def destination(self, double bearing, double distance):
cdef PyCCoordinate res=PyCCoordinate()
res.thisptr=self.thisptr.destination(bearing, distance)
return res
另一个问题:cython(也是python),不像c++,不知道重载,所以不能定义两个不同的构造函数(也不能定义其中一个为private),所以必须做dispatch手动,例如:
cdef class PyCCoordinate:
cdef Coordinate *thisptr
def __cinit__(self, x=None, y=None):
if x is None or y is None:#default, "private" constructor
pass #thisptr is initialized to NULL
else:
self.thisptr = new Coordinate(x,y) #
def __dealloc__(self):
del self.thisptr
def destination(self, double bearing, double distance):
cdef PyCCoordinate res=PyCCoordinate()
res.thisptr=self.thisptr.destination(bearing, distance)
return res