Python - 自定义向量类
Vector2d v0 版本:
# vector2d_v0.py
import math
from array import array
class Vector2d:
typecode = 'd' # 转换为字节时的存储方法,d 代表8个字节的双精度浮点数
def __init__(self, x, y):
self.x = float(x)
self.y = float(y)
# 使对象可迭代
def __iter__(self):
return (i for i in (self.x, self.y))
# 面向开发者的对象表示形式
def __repr__(self):
class_name = type(self).__name__
return '{}({!r}, {!r})'.format(class_name, *self)
def __str__(self):
return str(tuple(self))
# 对象的字节表现形式
def __bytes__(self):
return (bytes([ord(self.typecode)]) + # 将typecode转为字节序列
bytes(array(self.typecode, 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))
测试:
>>> from vector2d_v0 import Vector2d
>>> v1 = Vector2d(3,4)
>>> print(v1.x,v1.y)
3.0 4.0
# 因为v1 可迭代,所以可以进行拆包
>>> x, y = v1
>>> x, y
(3.0, 4.0)
# repr 函数调用Vector2d实例,得到的结果类似于构建实例的源码
>>> v1
Vector2d(3.0, 4.0)
# 使用eval函数,表明repr函数调用Vector2d实例得到的是对构造方法的准确表述
>>> v1_clone = eval(repr(v1))
>>> v1 == v1_clone
True
>>> print(v1)
(3.0, 4.0)
# 生成实例的二进制表示形式
>>> octets = bytes(v1)
>>> octets
b'd\x00\x00\x00\x00\x00\x00\x08@\x00\x00\x00\x00\x00\x00\x10@'
# 返回v1的模
>>> abs(v1)
5.0
>>> bool(v1), bool(Vector2d(0, 0))
(True, False)
Vector2d v1 版本: v0基础上,加入如下代码
# 目标: 将字节序列转化为实例
@classmethod
def frombytes(cls, octets):
"""
:param octets: Vector2d 实例的字节序列
:return: 实例
"""
typecode = chr(octets[0])
memv = memoryview(octets[1:]).cast(typecode)
print(*memv) # 构造函数的参数
return cls(*memv) # 返回一个新的Vector2d 实例
if __name__ == '__main__':
v1 = Vector2d(3, 4)
octets = bytes(v1)
v1_obj = Vector2d.frombytes(octets)
print(v1_obj is v1)
print(v1_obj == v1)
# out:
"""
3.0 4.0
False
True
"""
Vector2d v2版本 可散列的Vector2d
为了把Vector2d 实例变成可散列的,必须使用__hash__方法,还需__eq__方法已经实现
此外还需要向量不可变
import math
from array import array
class Vector2d:
typecode = 'd' # 转换为字节时的存储方法,d 代表8个字节的双精度浮点数
def __init__(self, x, y):
self.__x = float(x)
self.__y = float(y)
@property
def x(self):
return self.__x # 此处写self.x 会造成递归
@property
def y(self):
return self.__y
def __hash__(self):
return hash(self.x) ^ hash(self.y)
# 使对象可迭代
def __iter__(self):
return (i for i in (self.x, self.y))
# 面向开发者的对象表示形式
def __repr__(self):
class_name = type(self).__name__
return '{}({!r}, {!r})'.format(class_name, *self)
def __str__(self):
return str(tuple(self))
# 对象的字节表现形式
def __bytes__(self):
return (bytes([ord(self.typecode)]) + # 将typecode转为字节序列
bytes(array(self.typecode, 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))
@classmethod
def frombytes(cls, octets):
"""
:param octets: Vector2d 实例的字节序列
:return: 实例
"""
typecode = chr(octets[0])
memv = memoryview(octets[1:]).cast(typecode)
print(*memv) # out: 3.0 4.0 构造函数的参数
return cls(*memv)
if __name__ == '__main__':
v1 = Vector2d(3, 4)
v2 = Vector2d(3.1, 4.2)
print(hash(v1), hash(v2))
print(set([v1, v2])) # set 中的元素必须要可散列
# out:
"""
7 384307168202284039
{Vector2d(3.1, 4.2), Vector2d(3.0, 4.0)}
"""
Vector类: 用户定义的序列类型
基本的序列协议:
__len__
__getittem__
任何类,只要使用标准的签名和语义实现了这两个方法,就能用在任何期待序列的地方
import math
import reprlib
from array import array
class Vector:
typecode = 'd'
def __init__(self, components):
# arrya(typecode, components): components 为任何可以迭代的类型
self._components = array(self.typecode, components)
def __iter__(self):
return iter(self._components)
def __repr__(self):
"""
reprlib: 当Vector实例的分量超过6个,repr()生成的字符串就会使用...省略一部分。
:return:
"""
components = reprlib.repr(self._components)
# __repr__ run. components:array('d', [0.0, 1.0, 2.0, 3.0, 4.0, ...]), type(components):<class 'str'>
# print(f"__repr__ run. components:{components}, type(components):{type(components)}")
# 去除'[' 和 ')'
components = components[components.find('['):-1]
return f'Vector({components})'
def __str__(self):
return str(tuple(self))
def __bytes__(self):
return bytes([ord(Vector.typecode)]) + bytes(self._components)
def __eq__(self, other):
return tuple(self) == tuple(other)
def __abs__(self):
return math.sqrt(sum(x * x for x in self ))
def __bool__(self):
return bool(abs(self))
@classmethod
def frombytes(cls, octets):
typecode = chr(octets[0])
memv = memoryview(octets[1:]).cast(typecode)
print(f'memv: {memv}')
return cls(memv) # memv 不用拆包,是一个数组
测试:
>>> Vector([3.1, 4.2])
Vector([3.1, 4.2])
>>> Vector((3.1, 4.2))
Vector([3.1, 4.2])
>>> Vector(range(10))
Vector([0.0, 1.0, 2.0, 3.0, 4.0, ...])
本文来自博客园,作者:chuangzhou,转载请注明原文链接:https://www.cnblogs.com/czzz/p/15865083.html