『流畅的Python』第9章_符合Python风格的对象
Posted 叠加态的猫
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了『流畅的Python』第9章_符合Python风格的对象相关的知识,希望对你有一定的参考价值。
Python风格对象
以一个二元素向量对象为例
import math from array import array class Vector2d: typecode = ‘d‘ def __init__(self, x, y): self.x = float(x) self.y = float(y) def __iter__(self): # 使得Vector2d变成可迭代对象 # __iter__方法的实现使得本类可以被转化为tuple在内的其他可迭代类 return (i for i in (self.x, self.y)) def __repr__(self): class_name = type(self).__name__ # type(self): <class ‘__main__.Vector2d‘> return ‘{}({!r},{!r})‘.format(class_name, *self) def __str__(self): return str(tuple(self)) 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 __bytes__(self): """将Vector2d对象处理为二进制序列,格式我们自定""" # d:double类型数组 return (bytes([ord(self.typecode)]) + bytes(array(self.typecode, self))) # —————备用析构方法—————— @classmethod # 类方法,cls表示类本身 def frombytes(cls, octets): """对应于上面的方法,这里创建一个新的析构函数,使用特定的二进制序列构造Vector2d类实例""" typecode = chr(octets[0]) memv = memoryview(octets[1:]).cast(typecode) return cls(*memv) # 类名(参数),可见,类方法常用作备用析构 # —格式化输出— def angle(self): # math.atan(scope)输入为tan值 # math.atan2(y, x)输入为对应向量坐标(起点为原点) return math.atan2(self.y, self.x) def __format__(self, fmt_spec=‘‘): """格式化输出,如果格式末尾为p则输出极坐标, 输入其他格式为数字型格式,一个输入格式指定到两个数上,如:.3ep""" if fmt_spec.endswith(‘p‘): fmt_spec = fmt_spec[:-1] coords = (abs(self), self.angle()) out_fmt = ‘<{}, {}>‘ else: coords = self out_fmt = ‘({}, {})‘ components = (format(c, fmt_spec) for c in coords) return out_fmt.format(*components)
此时这个对象支持大部分python操作,
if __name__ == ‘__main__‘: b = bytes(Vector2d(3, 4)) print(Vector2d.frombytes(b)) print(format(Vector2d(1, 1), ‘.5fp‘))
(3.0, 4.0)
<1.41421, 0.78540>
但是一个重要的方法还是没能实现,__hash__,这关乎到对象是否可以被存入字典进行高速读取的属性,实际上可以hash对象需要三个条件:
-
需要__hash__方法
-
需要__eq__方法(已经实现)
-
需要对象不可变 # 实例的散列值关乎查找等使用方式,绝对不可以变化
也就是我们指定v.x=1(v为class实例)会报错才行,这需要一些其他操作:
class Vector2d: typecode = ‘d‘ def __init__(self, x, y): self.__x = float(x) self.__y = float(y) @property def x(self): return self.__x @property def y(self): return self.__y def __hash__(self): return hash(self.x) ^ hash(self.y)
其他方法不需要修改,
v1 = Vector2d(3, 4)
v2 = Vector2d(3.1, 4.2)
print(hash(v1), hash(v2))
# 7 384307168202284039
类方法和静态方法
# —对比类方法和静态方法— class Demo: @classmethod def klassmeth(*args): return args @ staticmethod def statmeth(*args): return args def normal(*args): return args
和实例方法不同,类方法第一个参数永远是类本身,所以常用于备用析构,静态方法没有默认的首位参数,测试如下:
print(Demo.klassmeth("hello"))
print(Demo.statmeth("hello"))
demo = Demo()
print(demo.normal("hello"))# (<class ‘__main__.Demo‘>, ‘hello‘)
# (‘hello‘,)
# (<__main__.Demo object at 0x000000000289F978>, ‘hello‘)
以上是关于『流畅的Python』第9章_符合Python风格的对象的主要内容,如果未能解决你的问题,请参考以下文章
《流畅的Python》Object References, Mutability, and Recycling--第8章