21.4_问题2:左项为ndarray实例的情况

21.4 问题2:左项为ndarray实例的情况

还有一个要解决的问题是ndarray实例为左项,Variable实例为右项的计算。比如以下代码。

$\begin{array}{rl} & {\mathrm{x = V�ariable(np.array([1.0])}}\\ & {\mathrm{y = np.array([2.0]) + x}} \end{array}$

在上面的代码中,左项是ndarray实例,右项是Variable实例。这时,左项ndarray实例的__add__方法被调用。当然,这里我们想让右项Variable实例的__radd__方法被调用。为此,我们需要指定运算符的优先级。具体来说,就是向Variable实例添加__array_priority__属性,并将其值设置为大的整数值。实际的代码如下所示。

class Variable: __array_priority__ = 200

通过向Variable类添加上面的代码,我们可以将Variable实例的运算符优先级设置为高于ndarray实例的运算符优先级。这样一来,即使左项是ndarray实例,右项的Variable实例的运算符方法也会被优先调用。

以上就是重载运算符时需要注意的地方。完成本步骤操作后,在使用DeZero时,我们就能通过运算符*和+将Variable实例和其他类型的数据连接在一起使用了。在下一个步骤,我们将添加/和-等运算符。

步骤22

运算符重载(3)

在上一个步骤,我们扩展了DeZero,使其支持*和+这两个运算符。运算符的种类很多,本步骤将实现对表22-1中运算符的支持。

表 22-1 本步骤中新增加的运算符

表22-1中的第1个方法__neg__(self)对应的是负数运算符,它是只有一个操作数项的运算符(这种运算符称为单目运算符)。因此,这个特殊方法只需要一个参数。剩下的是减法运算、除法运算和幂运算。正如前面提到的那样,这些运算对应的运算符是有两个操作数项的运算符(如a - b和a / b等)。对象可能是右项,也可能是左项,因此特殊方法有两个。不过对于幂运算,我们只考虑x**3这样的情况,也就是左项是Variable实例,右项是常数(2或3等int型数据)。

除表22-1中列出的运算符之外,还有其他类型的Python运算符,如a//b和a % b等。此外,还有a += 1和a -= 2等赋值运算符。本步骤只选择并实现那些可能会被频繁使用的操作符,至于其他运算符,请读者根据需要自行添加。本步骤的内容有些单调,大家可以选择跳过。

下面开始编写代码。首先复习一下添加新运算符的步骤

  1. 继承Function类并实现所需的函数类(例:Mul类)

  2. 使其能作为Python函数使用(例:mul函数)

  3. 为Variable类设置运算符重载(例:Variable.mul = mul)

我们将遵循上面的步骤添加新的运算符。首先是负数