Skip to content

Latest commit

 

History

History
76 lines (58 loc) · 3.84 KB

第1章-python数据模型-3.md

File metadata and controls

76 lines (58 loc) · 3.84 KB

如何使用特殊的方法 特殊方法需要了解的第一件事是,他们注定要被Python解释器调用,而不是被您调用。您不写my_object.__len__()。您应该写len(my_object),如果my_object是用户定义的类的一个实例,然后Python调用您实现的__len__实例方法。

但对于内置类型如表,字符串,字节数组等,解释器采用了一个便捷方法:CPython实现len()方法实际上返回的是在PyVarObject C结构体中ob_size字段的值,表示内存中的任何变量大小的内置对象。这比调用一个方法要快得多。

更多的并不是如此,特殊方法的调用往往是隐式的。好比说,for i in x这句话实际上会调用iter(x)这反过来又可能会调用x.__iter__(),如果它是可用的。

通常情况下,您的代码不应该有许多直接调用特殊方法的调用。除非您是做了很多的元编程,您应该实现特殊的方法而不是显式调用它们。唯一用户代码经常直接调用的方法是是__init__,在您自己的__init__中实现调用父类的初始化。

如果您需要调用一个特殊的方法,通常更好的是调用相关的内置功能,如len, iter, str等。

这些内置功能调用相应的特殊方法,但往往提供其他服务,同时,内置类型速度比的方法调用的快。 避免使用__foo__语法创建任意自定义属性,因为这样的名字可能在未来获得特殊的意义,即使它们现在是未使用的。

模拟数值类型 一些特殊的方法允许用户对象响应算子如 + 。我们将在第13章更详细的介绍,但在这里,我们的目标是通过另一个简单的例子进一步说明特殊方法的用法。 我们将实现一个类来表示2维向量,即如在数学和物理中使用的欧氏向量(见下图)

图1 2D向量相加的例子
### tips: 内置的complex类型可以用来表示二维向量,但是我们类可以推广到表示n维向量。在第14章中,我们将这样做。

我们将开始设计API通过为一个类写一个模拟控制台会话,后面我们可以用作doctest。下面的代码片段测试向量加法的照片(见上图)

>>> v1 = Vector(2, 4) 
>>> v2 = Vector(2, 1) 
>>> v1+v2 
Vector(4, 5)

注意+操作符如何产生一个向量结果并以一个友好的方式在控制台显示 内置函数abs返回的整数和浮点数的绝对值,和复数的模,所以为保持一致,我们的API也使用了abs来计算一个向量的大小

>>> v = Vector(3, 4) 
>>> abs(v)
5.0

我们还可以实现*操作符来执行向量乘法,即由一个数字乘以一个向量,以产生一个与原向量相同的方向和乘以原向量模的新的向量:

>>>v*3 
Vector(9, 12) 
>>> abs(v * 3) 
15.0

例1-2是一个向量类,通过特殊的方法__repr__,__abs__,__add__和__mul__的使用,实现所描述的操作符

from math import hypot


class Vector:

    def __init__(self, x=0, y=0):
        self.x = x
        self.y = y

    def __repr__(self):
        return 'Vector(%r, %r)' % (self.x, self.y)

    def __abs__(self):
        return hypot(self.x, self.y)

    def __bool__(self):
        return bool(abs(self))

    def __add__(self, other):
        x = self.x + other.x
        y = self.y + other.y
        return Vector(x, y)

    def __mul__(self, scalar):
        return Vector(self.x * scalar, self.y * scalar)

请注意,虽然我们实施了四个特殊的方法(除了__init__),它们中没有一个是类直接调用、或是在控制台列表中说明的类的典型用法中直接调用的。如前所述,Python解释器是调用特殊方法唯一的常客。在下一节中,我们讨论了每种特殊方法的代码。