欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Python中常见的特殊方法-魔术方法介绍

程序员文章站 2022-03-27 13:34:04
class Vector2d: ...: typecode = 'd' ...: def __init__(self,x,y): ...: self.__x = float(x) # 私有变量 ...: self.__y = float(y) ...: @property ...: def x(self): ...: # 读取,v1.x相同方式读取 ...: ....
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<len(self.shortcut_names):
    ...:                 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.csdn.net/weixin_40539952/article/details/107382510

相关标签: Python 魔术方法