1. 程式人生 > >【Python】【python-object.py】

【Python】【python-object.py】

初始 pam 實現 .py 最好 弧度 oat 函數調用 值方法

"""
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\[email protected]\x00\x00\x00\x00\x00\x00\[email protected]‘
#print(Vector2d.frombytes(r‘d\x00\x00\x00\x00\x00\x00\[email protected]\x00\x00\x00\x00\x00\x00\[email protected]‘)) #這種方式來驗證總報錯,暫時想不出好的驗證辦法
#驗證格式化
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\[email protected]‘
17
b‘f\xcd\xcc\x8c?\xcd\xcc\[email protected]‘
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】