购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

4.4 完善Vector类

Point类和Vector类看起来不错,但是还缺少一些细节。如果我们比较其中一个类的两个实例,Python可能无法确定它们是否相等,我们很快就会解决这个问题。此外,如果你记得的话,Python会将对象实例输出到控制台,给出它们所属的类名,并附带一个内存地址,这些信息对我们用处不大,我们也会对此进行完善。

4.4.1 检验相等性

请在shell中输入以下内容(不要忘记重新加载shell):

我敢打赌,你并没有对❶的结果感到惊讶:点当然与它自身相等。那❷呢?你感到吃惊吗?两个点的坐标完全相同,但是Python认为不同。难道(1,0)不等于(1,0)吗?它应该相等,但首先我们必须教Python如何比较同一个类的两个实例。如果同一个类的两个实例完全相同,即内存区域也相同,那么默认情况下Python就会认为它们相等。为了更明白一点,请在控制台中输入如下代码:

在Python看来,实例p是内存地址0x10baa3f60的实例,实例q是0x10c63b438的实例。别忘了你的实例的内存地址会与以上地址不同。我们必须告诉Python,通过检查投影是否足够接近来比较Point实例是否相同。回忆一下表4-1,通过构建名为__eq__(self,other)的方法,就可以重载==操作符。让我们在Point类和Vector类中都这样做。

在Point类中加入清单4-23中的代码(不要忘记导入nums)。

清单4-23 比较点是否相等的代码

在Vector类中加入清单4-24中的代码。

清单4-24 比较向量是否相等的代码

如你所见,两个代码的逻辑是相同的:将坐标与另一个给定实例进行比较。在这之前,我们做了两项重要的检查。一是检查我们是否在比较相同的实例,这种情况不需要任何其他操作,所以我们直接返回True。二是针对other不是Vector类的实例的情况。因为Python允许比较任意两个对象,所以可能会出现将Vector的实例和字符串进行比较的情况。如果检测到这种情况,即试图比较不同类的实例,则返回False,这样就结束了。这个比较模式会在后面反复出现,因为所有构建__eq__方法的类都会使用这种方法。

为了确保无误,让我们重复实验一下。不要忘记重新加载控制台以导入上一版本的代码,并输入以下代码:

搞定!现在Point类和Vector类的比较方法可以正常工作了。

4.4.2 字符串表示

如你所见,控制台对类的实例的介绍并不是特别有用:

如果使用str函数将实例转换为它的字符串表示,我们会得到相同的结果:

当将Vector实例的字符串表示输出到控制台时,我们会得到更有用的信息,如下所示:

该信息包含向量的坐标和范数。Python中的str()函数将类的实例转换为它的字符串表示。这个函数首先检查传递的参数是否拥有__str__方法。如果是,函数会调用它并返回结果;如果否,函数只返回默认的字符串表示,在上述例子中,是无用的内存地址。

让我们在类中构建__str__。在Point类中输入清单4-25中的代码。

清单4-25 Point类中覆盖原先的字符串表示

在Vector类中输入清单4-26中的代码。

清单4-26 Vector类中覆盖原先的字符串表示

我们将实例的属性包含在f字符串(f'')中。属性被放到大括号之间,Python调用它们的__str__方法来获得字符串表示对结果进行拼接。例如,你可以认为f字符串:

在Python中的含义如下:

现在,当对类的实例使用str()时,将输出更好的信息。让我们重新加载Python shell,并进行第二次尝试:

结构好多了,不是吗?

4.4.3 向量的工厂函数

工厂函数(factory function)是可以创建对象的函数。对于初始化需要一些计算的对象而言,工厂函数是一个好的选择。理想情况下,初始化器应该只需给出其类的属性,不做任何计算,为此,我们将使用工厂函数。

工厂函数还有助于提高代码的可读性。例如,如果你想创建从点 P 到点 Q 的向量,代码如下:

看起来比下面这个代码好得多:

不仅如此,第二个很可能会重复写很多次。这种情况表明,我们应该根据理论定义来抽象出对应的算法。在上面的例子中,对应的算法是通过两个有序点创建向量的方法,见公式(4.12)。

注意 :缺少抽象的问题很常见。代表某个具体概念的算法没有被正确地封装到拥有适当名称的函数或类中,这个现象经常发生。其主要缺点是,当抽象算法没有被很好地封装时,我们的大脑需要很长时间才能理解代码,而且相同的算法在许多地方被复制和粘贴,这使得它难以维护。

在geom2d中创建一个新文件,命名为vectors,并输入清单4-27中的代码。

清单4-27 向量工厂函数

这个文件定义了几个函数,都可以用来创建向量。第一个函数(make_vector_between)创建一个从点p到点q的向量。我们已经利用Point类的__sub__方法创建了点之间的向量。这是创建向量的一种便捷方法,如公式(4.12)所示:

接下来,名为make_versor的函数可以创建单位方向向量。单位方向向量经常被用来表达方向或朝向,所以我们需要一种便捷方式来创建它们。注意,单位方向向量的符号有一个小帽,如 u ˆ,表示它们的长度是单位长度。

最后,我们有make_versor_between函数来在两点之间创建一个单位方向向量,它调用make_vector_between函数,然后返回归一化的结果。结果的单位方向向量也可以用公式(4.13)来计算: h7jNPv/8GhQHwRk7pCTAJBDHz3Zz6qRZale0IVrIHMkcNS4/vLp4ntwEgmBQsuFL

点击中间区域
呼出菜单
上一章
目录
下一章
×