如何在 PyO3 中实现 python 运算符

N0n*_*ame 4 python rust pyo3

我正在尝试为我的数学库在 Rust 中实现一个向量类。

#[pyclass]
struct Vec2d {
    #[pyo3(get, set)]
    x: f64,
    #[pyo3(get, set)]
    y: f64
}
Run Code Online (Sandbox Code Playgroud)

But I can't figure out how I can overload the standard operators (+, -, *, /)

I Tried implementing the Add trait from std::ops with no luck

impl Add for Vec2d {
    type Output = Vec2d;
    fn add(self, other: Vec2d) -> Vec2d {
        Vec2d{x: self.x + other.x, y: self.y + other.y }
    }
}
Run Code Online (Sandbox Code Playgroud)

I also tried adding __add__ method to the #[pymethods] block

fn __add__(&self, other: & Vec2d) -> PyResult<Vec2d> {
    Ok(Vec2d{x: self.x + other.x, y: self.y + other.y })
}
Run Code Online (Sandbox Code Playgroud)

but still does not work.

With the second approach I can see that the method is there, but python doesn't recognize it as operator overload

In [2]: v1 = Vec2d(3, 4)
In [3]: v2 = Vec2d(6, 7)
In [4]: v1 + v2
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-4-08104d7e1232> in <module>()
----> 1 v1 + v2

TypeError: unsupported operand type(s) for +: 'Vec2d' and 'Vec2d'

In [5]: v1.__add__(v2)
Out[5]: <Vec2d object at 0x0000026B74C2B6F0>
Run Code Online (Sandbox Code Playgroud)

Abd*_*P M 5

根据PyO3文档,

Python 的对象模型为不同的对象行为定义了几个协议,如序列、映射或数字协议。PyO3 为它们中的每一个定义了单独的特征。要提供特定的 Python 对象行为,您需要为您的结构实现特定的特征。

重要说明,每个协议实现块都必须用#[ pyproto]属性进行注释。

__add____sub__等被内定义PyNumberProtocol性状。

所以你可以 PyNumberProtocol为你的Vec2d结构实现重载标准操作。

#[pyproto]
impl PyNumberProtocol for Vec2d {
    fn __add__(&self, other: & Vec2d) -> PyResult<Vec2d> {
            Ok(Vec2d{x: self.x + other.x, y: self.y + other.y })
   }
}
Run Code Online (Sandbox Code Playgroud)

此解决方案未经测试,有关完整的工作解决方案,请查看 @Neven V 的答案。