第十章 序列的修改、散列和切片
1.切片是一个对象
slice(start, stop, stride)
它还有一个.indices(n)的方法,能优雅地处理过界与索引丢失
如:
slice(None, 10, 2).indices(5) #说明这个切片长度为5
然后切片就会变成slice(0, 5, 2)
2.判断是不是数字
用isinstance(a, numbers.integral) 判断是不是整型
1.切片是一个对象
slice(start, stop, stride)
它还有一个.indices(n)的方法,能优雅地处理过界与索引丢失
如:
slice(None, 10, 2).indices(5) #说明这个切片长度为5
然后切片就会变成slice(0, 5, 2)
2.判断是不是数字
用isinstance(a, numbers.integral) 判断是不是整型
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 <len(self.components): return self._components[pos] msg = '{.__name__!r} object has no attribute {!r}' raise AttributeError(msg.format(cls, name))
但我们又不想这样去让他赋值,通过__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(根据这代码瞎猜的)。