本文将在上一篇二维向量Vector2d类的基础上定义表示多维向量的Vector类。版本一:兼容Vector2d类代码如下:fromarrayimportarrayimportreprlibimportmathclassVector:typecode='d'def__init__(self,components):self._components=array(self.typecode,components)#多维向量存储数组def__iter__(self):returniter(self._components)#构建迭代器def__repr__(self):components=reprlib.repr(self._components)#有限长度表示components=components[components.find('['):-1]return'Vector({})'.format(components)def__str__(self):returnstr(tuple(self))def__bytes__(self):return(bytes([ord(self.typecode)])+bytes(self._components))def__eq__(self,other):returntuple(self)==tuple(other)def__abs__(self):returnmath.sqrt(sum(x*xforxinself))def__bool__(self):returnbool(abs(self))@classmethoddeffrombytes(cls,octets):typecode=chr(octets[0])memv=memoryview(octets[1:]).cast(typecode)returncls(memv)#因为构造函数的入参是数组,所以不需要使用reprlib.repr()函数中*解压Safeexp用于生成大型结构或递归结构的ression,例如:>>>Vector([3.1,4.2])Vector([3.1,4.2])>>>Vector((3,4,5))Vector([3.0,4.0,5.0])>>>矢量(范围(10))矢量([0.0,1.0,2.0,3.0,4.0,...])超过6个元素表示为...版本2:支持切片Python协议是一个非正式的接口,仅在文档中定义,不在代码中定义。比如Python的序列协议只需要__len__和__getitem__两个方法,Python的迭代协议只需要__getitem__一个方法。它们不是正式的接口,而是Python程序员的默认约定。切片是序列特有的操作,所以Vector类必须实现序列协议,即__len__和__getitem__这两个方法。代码如下:def__len__(self):returnlen(self._components)def__getitem__(self,index):cls=type(self)#获取实例所属的类ifisinstance(index,slice):#如果index是aslicesliceobjectreturncls(self._components[index])#调用构造函数返回一个新的Vector实例elifisinstance(index,numbers.Integral):#如果index是整数returnself._components[index]#直接返回元素else:msg='{cls.__name__}indicesmustbeintegers'raiseTypeError(msg.format(cls=cls))测试一下:>>>v7=Vector(range(7))>>>v7[-1]#<1>6.0>>>v7[1:4]#<2>向量([1.0,2.0,3.0])>>>v7[-1:]#<3>向量([6.0])>>>v7[1,2]#<4>Traceback(mostrecentcalllast):...TypeError:VectorindicesmustbeintegersVersion3:动态访问属性是通过__getattr__实现的,通过__setattr__,我们可以动态访问Vector类的属性。这支持像v.my_property=1.1这样的赋值。如果使用__setitem__方法,则只支持v[0]=1.1。代码如下:shortcut_names='xyzt'#4个组件属性名def__getattr__(self,name):cls=type(self)#获取实例所属的类iflen(name)==1:#只有一个字母pos=cls.shortcut_names.find(name)if0<=pos
