1.自定义向量类
class Ve:
def __init__(self, x, y):
self.x = x
self.y = y
def __iter__(self):
return (i for i in (self.x, self.y))
def __str__(self):
return str(tuple(self))
def __eq__(self, other):
return tuple(self) == tuple(other)
def __abs__(self):
return self.x*self.x + self.y*self.y
def __bool__(self):
return bool(abs(self))
obj1 = Ve(1, 2)
obj2 = Ve(0, 0)
print(str(obj1))
print(obj1 == obj2)
print(bool(obj1), bool(obj2))
print(abs(obj1))
print(obj1)
for i in obj2:
print(i)
输出
(1, 2) 注释: 1.定义__str__方法实现了str()方法,其他同理
False 2.参数为 self 即对象本身
True False 3.__eq__方法用于判断向量是否相等
5 4.__abs__方法用于计算向量模的平方和
0 5.__bool__方法用于计算向量模是否为0并返回布尔值
0 6.__iter__方法负责实现迭代,允许对象 for 循环
(1, 2) 7.输出对象显示, 由__str__ 和 __iter__共同决定, __str__决定显示
2.格式化显示
分为 format() 和 str.format()
format()
a = 10
value = 1/3.11
h = format(value, '0.3f') 小数点后保留三位
y = format(10, 'b') 转化为2进制
j = format(1/3, '.3%') 百分号后保留三位
print([i for i in [h, y, j]])
['0.322', '1010', '33.333%']
str.format()
value = 10/3.11
result = '{result: 0.5f}'.format(result=value) 小数点后保留5位
print(result)
3.21543
注意:如果类没有定义 format 方法, 从 object 继承的方法会返回 str(obj)
因为我们前面Ve类定义了 str 方法,因此
format(obj1) 返回 (1, 2) 执行的是__str__方法
3.实现向量类的 format 方法
def __format__(self, format_spec):
result = (format(c, format_spec) for c in self)
return '({}, {})'.format(*result)
引用 format方法, * 可以拆元组
obj1 = Ve(1, 2)
format(obj1, '.2f')
(1.00 2.00)
4.拓展
新极坐标显示向量
规定 format(obj, 'xxxp') 以 p 结尾则极坐标显示
极坐标显示第一个参数为模长的平方,第二个为弧度
def angle(self):
return math.atan2(self.y, self.x)
定义计算弧度函数
对 format 函数做修改
def __format__(self, format_spec=''):
if format_spec.endswith('p'):
format_spec = format_spec[:-1]
obj = (abs(self), self.angle()) 对象即元组
else:
obj = self 对象即元组
result = (format(c, format_spec) for c in obj) 一个生成器
return '({}, {})'.format(*result)
def angle(self):
return math.atan2(self.y, self.x)
obj1 = Ve(1, 1)
print(format(obj1, '0.5fp'))
(2.00000, 0.78540)
原功能不影响
5.可散列的向量类
实现对象的只读性----x, y分量只读
class Ve:
def __init__(self, x, y):
self.__x = x 设置私有属性
self.__y = y
@property 装饰器实现类方法变类属性
def x(self): 实现只读属性, 不能在实例化后修改, 否则报错
return self.__x 如果属性名不为x, 修改不会报错, 但是对象的x值不会改变
@property
def y(self): 实质是属性方法的覆盖
return self.__y
def __iter__(self):
return (i for i in (self.__x, self.__y))
def __str__(self):
return str(tuple(self))
obj = Ve(3, 4)
print(obj)
print(obj.x)
(3, 4) 依然如此返回
3
当向量不可变后,才能实现其 hash 方法
要想创建可散列的类型, 只需正确实现 __hash__ 和 __eq__ 方法, 但是实例的散列值绝不应该变化
简易实现 complex()函数
def new_complex(x, y):
if x == 0:
return '{}j'.format(y)
else:
return '({}+{}j)'.format(x, y)
result = new_complex(0, 1) 实际上, 真正的complex()函数还会接收复数类如
result1 = new_complex(1, 0) 3+4j, '3+4j' 作为参数并返回
print(result, result1) 若判断参数包含复数类型则直接返回
1j (1+0j)
设置 hash 和 repr 方法
def __hash__(self): 哈希函数
return hash(self.x) ^ hash(self.y)
def __repr__(self):
class_name = type(self).__name__
return '{}({!r}, {!r})'.format(class_name, *self) 实例化对象显示
obj = Ve(4, 4)
print(hash(obj))
print(repr(obj))
16 Ve(4, 4)
6.使用 slots 类属性节省空间
默认情况下, Python在各个实例中名为 __dict__的字典里存储实例属性, 使用散列表提升速度但字典会消耗大量内存
通过__slots__类属性,能节省大量内存,方法是让解释器在元组中存储实例属性
设置类属性
class Ve:
__slots__ = ('__x', '__y', '__weakref__') 以元组存储, 添加弱引用属性
设置 __slots__ 属性后,实例不能再有 __slots__ 中所列名称外的其他属性
要注意的问题
1.当处理上百万数据时作用明显尤其对于列表
2.每个子类都要定义__slots__属性,因为解释器会忽略继承的__slots__属性
3.实例只能拥有__slots__中列出的属性
7.覆盖类属性
设置类属性
实例覆盖
class Ve:
test = 'd'
其他构造方法省略
obj = Ve(4, 4)
print(Ve.test, obj.test)
obj.test = 'f'
print(obj.test)
d d
f 针对每个不同的实例做特定的修改
覆盖类属性有两种办法, 实例覆盖类属性和继承类覆盖类属性
继承类覆盖
class Vf(Ve):
test = 'h'
obj = Vf(1, 2)
print(Vf.test, obj.test)
h h 多用于Django框架中