码迷,mamicode.com
首页 > 编程语言 > 详细

【Python】【python-object.py】

时间:2017-10-13 10:25:29      阅读:194      评论:0      收藏:0      [点我收藏+]

标签:数值   中继   相等   影响   序列   函数调用   将实例   解释器   3.1   

"""
from array import array
print(bytes([9])) #当source参数是一个可迭代对象,那么这个迭代对象的元素都必须符合0 <= x < 256,以便可以初始化到数组里
print(bytes(array(‘d‘,(1,2))))
‘‘‘
首先引入
from array import array
然后list到array直接传参数进构造函数就可以。(不知道是不是叫构造函数)
np.array(‘d‘,[1,2,3])
转回来的话调用tolist函数
_.tolist()
‘‘‘

#例子9-4 比较classmethod和staticmethod
class Demo:
@classmethod
def klassmeth(*args):
return args
@staticmethod
def statmeth(*args): #行为和普通函数相似
return args
print(Demo.klassmeth()) #(<class ‘__main__.Demo‘>,)
print(Demo.klassmeth(‘spam‘)) #(<class ‘__main__.Demo‘>, ‘spam‘)
print(Demo.statmeth()) #()
print(Demo.statmeth(‘spam‘)) #(‘spam‘,)

"""
#9.2 再谈向量类
#例子9-2 定义的都是特殊方法
import array
import math
class Vector2d:
typecode = ‘d‘
‘‘‘
def __init__(self,x,y):
self.x = float(x) #转换称浮点数,尽早捕获错误,以防调用Vector2d函数时传入不当参数
self.y = float(y)
‘‘‘
def __iter__(self):
return (i for i in (self.x,self.y)) #把Vector2d实例变成可迭代对象,这样才能拆包(例如,x,y = my_vector)。
def __repr__(self):
class_name = type(self).__name__
return ‘{}({!s},{!s})‘.format(class_name,*self) #因为Vector2d实例是可迭代对象,所以**self会把x和y分量提供
def __str__(self):
return str(tuple(self)) #用可迭代实例可生成元祖
def __bytes__(self): #python有个独特的特性:类属性可用于为实例属性提供默认值。虽然此时实例并无属性typecode,但是此时它是默认取自Vector2d.typecode
#但是。如果为不存在的实例属性赋值,会新建实例属性。假如我们为typecode实例属性赋值,那么同名类属性不受影响。然而,自此之后,实例读取的self.typecode是实例属性,也就是
#把同名类属性覆盖了(但通过类访问这个属性,值还是不变的)。借助这一特性,可以为各个实例的typecode属性定制不同的值
return (bytes([ord(self.typecode)]) + bytes(array.array(self.typecode,self))) #为了生成自己序列,我们typecode转换称字节序列,然后迭代Vector2d实例,得到一个数组,再把数组转换称字节序列
@classmethod
def frombytes(cls,octets):
typecode = chr(octets[0])
memv = memoryview(octets[1:]).cast(typecode)
return cls(*memv)
def __eq__(self, other):
return tuple(self) == tuple(other)
def __abs__(self):
return math.hypot(self.x,self.y) #为了比较所有分量,构建元祖。对Vector2d实例来说,可以这样做,不过仍有问题。有了这种方式,再两个操作数都是Vector2d实例时可用,不过那Vector2d实例与其他
#具有相同数值的可迭代对象相比,结果也是True(如Vector2d(3,4) == [3,4])。这个行为可视作特性,也可视作缺陷。以后讲到运算符重载时才能进一步讨论
def __bool__(self):
return bool(abs(self))

def angle(self): #计算角度
return math.atan2(self.x,self.y)

def __format__(self, format_spec=‘‘): #自定义格式代码:如果格式说明拂以‘p‘结尾,那么在极坐标中显示向量,即<r,x>,其中r是模,x是弧度
if format_spec.endswith(‘p‘):
format_spec = format_spec[:-1]
coords = (abs(self),self.angle())
outer_fmt = ‘<{},{}>‘
else:
coords = self
outer_fmt = ‘({},{})‘
components = (format(c,format_spec) for c in coords)
return outer_fmt.format(*components)

#可散列的:属性必需是不变的,所以要将实例的两个属性设置成只读,因为现在我们还可以通过v1.x 的方式为属性赋值. 【步骤】1??#修改构造方法2?? #还要设置@property3??实现__hash__方法(只有不可变的向量才能实现这个方法)
#这个方法应该返回一个整数,理想情况下还要考虑对象属性的散列值(__eq__方法也要使用),因为相等的对象应该具有相同的散列值。
#根据官方文旦,最好使用位运算符异或混合各分量的散列值

def __init__(self,x,y):
self.__x = float(x)
self.__y = float(y)

@property
def x(self): #这样就可以通过self.x来把它当公开属性读取
return self.__x
@property
def y(self):
return self.__y

def __hash__(self):
return hash(self.x)^hash(self.y) #这里可以直接用self.x代替self.__x是因为用@property设置了读取方法,所以其他方法也是通过这样来读取公开属性


"""
v1 = Vector2d(3,4)
print(v1.x,v1.y) #3.0 4.0 .实例分量可直接通过属性访问(无需调用读值方法)
x,y = v1
print(x,y) #3.0 4.0 .实例可拆包成变量元祖
print(v1) #(3.0, 4.0) .print函数会调用str函数
v1 #在控制台,这里会打印出:Vector2d(3.0,4.0)
v1_clone = eval(repr(v1)) #这里用eval函数,表明repr函数调用Vector2d实例得到的是对构造方法的准确表述
print(v1_clone == v1) #True
print(abs(v1)) #5.0
print(bool(v1),bool(Vector2d(0,0))) #True False
octets = bytes(v1)
print(octets) #b‘d\x00\x00\x00\x00\x00\x00\x08@\x00\x00\x00\x00\x00\x00\x10@‘
#print(Vector2d.frombytes(r‘d\x00\x00\x00\x00\x00\x00\x08@\x00\x00\x00\x00\x00\x00\x10@‘)) #这种方式来验证总报错,暂时想不出好的验证办法
#验证格式化
print(format(Vector2d(1,1),‘p‘)) #<1.4142135623730951,0.7853981633974483>
print(format(Vector2d(1,1),‘.3ep‘)) #<1.414e+00,7.854e-01>
print(format(Vector2d(1,1),‘0.5fp‘)) #<1.41421,0.78540>

#验证散列性
v3 = Vector2d(3,4)
v4 = Vector2d(3.1,4.2)
v5 = Vector2d(3,4)
print(hash(v3),hash(v4)) #7 384307168202284039
print(hash(v3),hash(v5)) #7 7
print(v3 == v5) #True

#9.7私有属性和"受保护的"属性
v6 = Vector2d(3,4)
print(v6.__dict__)
print(v6._Vector2d__x)
v6._Vector2d__x = 5.0
print(v6.__dict__)
#这样看来,太危险了,同时还有人不喜欢这个语法,所以出现了受保护的属性,python解释器虽然不会对使用单个下划线的属性做特殊处理,但是很多python程序员严格遵守这个约定,不会在类外部访问单下划线这种受保护的属性(约定这是私有的)

#9.8 使用__slots__类属性节省空间:只有在需要处理大数据时才能显现出价值,正常情况下就不要这么麻烦的取创建这种不寻常的类了
#默认情况下,python在各个实例中名为__dict__的字典里存储实例属性。为了使用低层的散列表提升访问速度,字典会消耗大量内存。如果要处理数百外各属性不多的实例,这种方式可节省大量内存,方法是让解释器在元祖中存储实例属性,而不用字典
#子类不继承,只有当前类有效
class V:
__slots__ = (‘__x‘,‘__y‘)
#不过,也有要注意的
#1?? 每个子类都要定义__slots__属性,因为解释器会忽略继承的
#2??实例只能拥有__slots__中列出的属性,除非把‘__dict__‘加入__slots__中,不过这样做就失去了节省内存的功效
#3??如果不把__weakref__加入__slots__,实例就不能作为弱引用的目标

#9.9 覆盖类属性
#例子9-13 设定从类中继承的typecode属性,自定义一个实例属性
v7 = Vector2d(1.1,2.2)
dumpd = bytes(v7)
print(dumpd)
print(len(dumpd))
v7.typecode = ‘f‘
dumpf = bytes(v7)
print(dumpf)
print(len(dumpf))
‘‘‘
b‘d\x9a\x99\x99\x99\x99\x99\xf1?\x9a\x99\x99\x99\x99\x99\x01@‘
17
b‘f\xcd\xcc\x8c?\xcd\xcc\x0c@‘
9
‘‘‘
#例子9-14 ShortVector2d是Vector2d的子类,只用于覆盖typecode的默认值
class ShortVector2d(Vector2d):
typecode = ‘f‘
sv = ShortVector2d(1/11,1/27)
print(sv) #(0.09090909090909091, 0.037037037037037035)
print(len(bytes(sv))) #9
#【分析】这也说明了我在Vector2d.__repr__方法中为什么没有硬编码class_name的值,而是使用type(self).__name__,如果硬编码的话,那么Vector2d的子类要覆盖__repr__方法,只是为了修改class_name的值。从实例的类型中
#读取类名,__repr__方法就可以放心继承
"""





























































【Python】【python-object.py】

标签:数值   中继   相等   影响   序列   函数调用   将实例   解释器   3.1   

原文地址:http://www.cnblogs.com/suren2017/p/7659234.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!