python描述符魔术方法_Python中常见的特殊方法-魔术方法介绍

本文介绍了一个用 Python 实现的 Vector 类的设计与实现细节,包括如何通过私有变量和属性装饰器来封装数据,以及如何重载特殊方法以支持数学运算和格式化输出。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

class Vector2d:

...: typecode = 'd'

...: def __init__(self,x,y):

...: self.__x = float(x) # 私有变量

...: self.__y = float(y)

...: @property

...: def x(self):

...: # 读取,v1.x相同方式读取

...: return self.__x

...: @property

...: def y(self):

...: return self.__y

...: def __iter__(self):

...: return (i for i in (self.x,self.y))

...: def __repr__(self):

# eval(repr(v1))==v1

...: class_name = type(self).__name__

...: return '{}({!r},{!r})'.format(class_name,*self)

...: def __str__(self):

# print调用该方法

...: return str(tuple(self))

...: def __bytes__(self):

# 转为字节码

...: return (bytes([ord(self.typecode)]) + bytes(array(self.typecode,self)))

...: @classmethod

...: def from_bytes(cls,octets):

# Vector2d.from_bytes(bytes(v1)) == v1

...: typecode = chr(octets[0])

...: memv = memoryview(octets[1:]).cast(typecode) # memoryview是数组的一种

...: return cls(*memv)

...: def __eq__(self,other):

# 注意特性[3.0,4.0] == print(v1)

...: return tuple(self) == tuple(other)

...: def __abs__(self):

# 计算模长

...: return math.hypot(self.x,self.y)

def __bool__(self):

# bool(v1),若abs(v1)==0则返回Flase

...: return bool(abs(self))

...: def angle(self):

...: return math.atan2(self.y,self.x)

...: def __format__(self,fmt_spec=''):

# 极坐标形式

...: if fmt_spec.endswith('p'):

...: fmt_spec = fmt_spec[:-1]

...: cood = (abs(self),self.angle())

...: outer_fmt = ''

...: else:

...: cood = self

...: outer_fmt = '({},{})'

...: components = (format(c,fmt_spec) for c in cood) # 数字的小格式

...: return outer_fmt.format(*components)

...: def __hash__(self):

# 散列化

...: return hash(self.x)^hash(self.y)

class Vector:

...: typecode = 'd'

...: def __init__(self,components):

...: self._components = array(self.typecode,components)

...: def __iter__(self):

...: return iter(self._components)

...: def __repr__(self):

...: components = reprlib.repr(self._components) # 将超长变量变成...

...: components = components[components.find('['):-1] # 将数组形式进行提取,find函数返回位置

...: return 'Vector({})'.format(components)

...: def __str__(self):

...: return str(tuple(self))

...: def __bytes__(self):

...: return (bytes([ord(self.typecode)])+bytes(self._components))

...: def __hash__(self):

...: hashes = map(hash,self._components)

...: return functools.reduce(operator.xor,hashes,0)# 异或运算需要设置0为初始值,以防报错

...: def __eq__(self,other):

...: return (len(self)==len(other)) and all(a==b for a,b in zip(self,other))

...: def __abs__(self):

...: return math.sqrt(sum(x*x for x in self))

...: def __bool__(self):

...: return bool(abs(self))

...: def __len__(self):

...: return len(self._components)

...: def __getitem__(self,index):

...: # 定义了该方法和len方法就是实现鸭子类型,序列

...: cls = type(self)# 备用

...: if isinstance(index,slice):

...: return cls(self._components[index]) # 如果是切片则返回实例对象

...: def __getattr__(self,name):

...: # 当属性查找失败的时候会调用该方法

...: cls = type(self)

...: if len(name)==1:

...: pos = cls.shortcut_names.find(name)

...: if 0<=pos

...: return self._components[pos]

...: msg = '{.__name__!r} object has no attribute {!r}'

...: raise AttributeError(msg.format(cls,name))

...: def __setattr__(self,name,value):

...: # 防止赋值导致的不一致,与getattr配套使用

...: cls =type(self)

...: if len(name)==1:

...: if name in cls.shortcut_names:

...: error = 'readonly attribute {attr_name!r}'

...: elif name.islower():

...: error = "can't set attributes 'a' to 'z' in {cls_name!r}"

...: else:

...: error = ''

...: if error:

...: msg = error.format(cls_name=cls.__name__,attr_name=name) # 根据错误直接赋值

...: raise AttributeError(msg)

...: super.__setattr__(name,value) # 无error把子类方法委托给超类,必须这么做

...: def angle(self,n):

...: r = math.sqrt(sum(x*x for x in self[n:]))

...: a = math.atan2(r,self[n-1])

...: if (n==len(self)-1) and (self[-1]<0):

...: return math.pi*2 -a

...: else:

...: return a

...: def angles(self):

...: # 计算角度和模

...: return (self.angle(n) for n in range(1,len(self)))

...: def __format__(self,fmt_spec=''):

...: if fmt_spec.endswith('h'):

...: fmt_spec = fmt_spec[:-1]

...: coords = itertools.chain([abs(self)],self.angles()) # 返回一个迭代序列

...: out_fmt = ''

...: else:

...: coords = self

...: out_fmt = '({})'

...: components = (format(c,fmt_spec) for c in coords)

...: return out_fmt.format(','.join(components))

...: @classmethod

...: def frombytes(cls,octets): # 类方法的第一个参数必定是cls

...: typecode = chr(octets[0])

...: memv = memoryview(octets[1:]).cast(typecode)

...: return cls(memv) # 返回一个类对象,不再拆包

本文地址:https://blog.youkuaiyun.com/weixin_40539952/article/details/107382510

如您对本文有疑问或者有任何想说的,请点击进行留言回复,万千网友为您解惑!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值