3.目前我们vector类很大,并且不支持v1.x去访问x方向上的分量,但我们又想做到,怎么实现呢?
通过__getattr__方法:
shortcut_names = "xyzt"
def __getattr__(self, name):
cls = type(self)
if len(name) == 1:
pos = cls.shortcut_names.find(name)
if 0 <= pos
但我们又不想这样去让他赋值,通过__setattr__:
def __setattr__(self, name, value):
cls = type(self)
if len(name) == 1:
if name in cls.shortcut_names:
error = 'readonly attributes {attr_name!r}'
elif name.islower():
error = "can't set attribues 'a' to 'z' in {cls_name!r}"
else:
error = ''
if error:
raise ArithmeticError(error.format(cls_name=cls.__name__, attr_name=name))
super().__setattr__(name, value)
这告诉我们实现了getattr 后通常要实现setattr
4.接下来是比较牛逼的技术了
因为我们要让我们这个类变得散列,所以我们得实现hash方法
请看如何实现的
def __hash__(self):
coord = (hash(x) for x in self._components)
return functools.reduce(operator.xor, coord, 0)
此方法与使用map生成coord是一样的
这里:
1.。使用了操作符函数代替了异或符号, operator.xor
2. reduce返回一个聚合值,并且reduce的默认值——第三个参数最好设置
同时到了这一步,我们会发现我们之前的__eq__有点不太好了,因为它需要复制一份元组,效率比较低,
当数据增大时,我们需要更快地方法。这思路有点像生成器的原理。
def __eq__(self, other):
return len(self) == len(other) and all(a == b for a, b in zip(self, other))
以上这句挺有味道,因为它先比较长度,避免zip终止过早。同时使用了all,all函数接受一个可迭代对象并且返回一个布尔值,这个可迭代对象中的迭代值一定得是bool(根据这代码瞎猜的)。