符合Python风格的对象
定义一个Python风格的向量类,让它:
- 支持用于生成对象其他表示形式的内置函数(通过定义
__repr__
、__format__
函数实现); - 使用一个类方法实现备选构造方法;
- 扩展内置的format()函数和str.format()方法使用的格式微语言(如,可以通过指定
format(Vector, 'p')
来输出向量的极坐标表示形式); - 实现只读属性;
- 把对象变成可散列的,通过给出正确
__hash__
方法定义; - 利用
__slots__
节省内存(此处略)。
from array import array
import math
class Vector2d:
typecode = 'd'
def __init__(self, x, y):
self.__x = float(x) #使用双下对类属性进行标记,将其标记为私有的
self.__y = float(y) #使用双下对类属性进行标记,将其标记为私有的
@property #property装饰器将读值方法标记为特性,读值方法与公开属性同名
def x(self):
return self.__x
@property
def y(self):
return self.__y
def __hash__(self): #实现了__hash__和__eq__方法之后,可以是Vector类对象变为可散列的.
return hash(self.x) ^ hash(self.y)
def __iter__(self):
return (i for i in (self.x, self.y)) #定义__iter__方法,将vector2d变为可迭代对象,
#这样做才能对vector2d对象进行拆包分解, 如 x, y = Vector2d这样的语句是合法的
def __repr__(self):
class_name = type(self).__name__
return '{}({!r},{!r})'.format(class_name, *self)
#__repr__方法使用{!r}获取各个分量的表示形式, 然后插值, 构成一个字符串. 由于Vector2d
#实例是可迭代对象, 因此*self会把x和y分量提供给format函数
def __str__(self):
return str(tuple(self))
def __bytes__(self):
return (bytes([ord(self.typecode)]) + bytes(array(self.typecode, self)))
#将Vector2d实例转化为字节序列
def __eq__(self, other):
return tuple(self) == tuple(other) #既可以视作特性, 也可以视作缺陷
def __abs__(self):
return math.hypot(self.x, self.y) #计算绝对值即求这个向量的模长
def __bool__(self):
return bool(abs(self))
# def __format__(self, fmt_spec=''):
# components = (format(c, fmt_spec) for c in self) #使用python内置的format函数,将fmt_spec格式通过迭代的方法应用到两维的变量上
# return '({}, {})'.format(*components) #再通过str.format进行格式化输出
def angle(self):
return math.atan2(self.x, self.y)
def __format__(self, fmt_spec):
if fmt_spec.endswith('p'): #现在可以使用format(v,'p')的方式,以极坐标的形式格式化输出向量
fmt_spec = fmt_spec[:-1]
coords = (abs(self), self.angle)
outer_fmt = '<{}, {}>'
else:
coords = self
outer_fmt = '({}, {})'
components = (format(c, fmt_spec) for c in coords)
return outer_fmt.format(*components)
@classmethod #通过frombytes将字节序列转化为Vector2d。
#使用装饰器classmethod,实现了备选构造方法
def frombytes(cls,octets):
typecode = chr(octets[0])
memv = memoryview(octets[1:]).cast(typecode)
return cls(*memv)