python中forward_符合python风格的对象
python自帶的對象擁有很多有趣的行為,用戶自己定義的類對象也可以實現跟python對象相同的行為。
對象的表示形式
python關于對象的表示提供了兩種形式:
repr()
便于開發者理解的返回對象的字符串形式
str()
便于用戶理解的返回對象的字符串形式
也正是對象的__repr__和__str__兩個特殊方法為repr()和str()提供支持。另外還有兩個方法,__bytes__和__format__。__bytes__方法跟__str__類似:bytes()函數調用它獲取對象的字節序列表示形式;__format_-方法會被內置的format()函數和str.format()方法調用。
向量類
自己定義一個Vector2d類,我們期望他能有下面的表現形式。
1 >>> v1 = Vector2d(3, 4)2 >>> print(v1.x, v1.y)3 3.0 4.0
4 >>> x, y =v15 >>>x, y6 (3.0, 4.0)7 >>>v18 Vector2d(3.0, 4.0)9 >>> v2 =eval(repr(v1))10 >>> v1 ==v211 True12 >>> print(v1)13 (3.0, 4.0)14 >>> octets =bytes(v1)15 >>>octets16 b'd\\x00\\x00\\x00\\x00\\x00\\x00\\x08@\\x00\\x00\\x00\\x00\\x00\\x00\\x10@'
17 >>>abs(v1)18 5.0
19 >>>bool(v1), bool(Vector2d(0, 0))20 (True, False)
實現代碼如下:
1 importmath2 from array importarray3 classVector2d:4 """
5 自定義一個二維向量類6 """
7 typecode = 'd'
8 def __init__(self, x, y):9 self.x =x10 self.y =y11
12 def __iter__(self):13 return (i for i in(self.x, self.y))14
15 def __repr__(self):16 return '{}({!r}, {!r})'.format(type(self).__name__, self.x, self.y)17
18 def __str__(self):19 return str(tuple(self)) #已經實現了__iter__方法,self實例是可迭代對象
20
21 def __eq__(self, other):22 return tuple(self) ==tuple(other)23
24 def __abs__(self):25 returnmath.hypot(self.x, self.y)26
27 def __bool__(self):28 returnbool(abs(self))29
30 def __bytes__(self):31 return bytes([ord(self.typecode)])+bytes(array(self.typecode, self))32
33 v1 = Vector2d(3, 4)34 print(v1.x, v1.y)35 #3.0 4.0
36 x, y =v137 print(x, y)38 #(3.0, 4.0)
39 print(v1)40 #Vector2d(3.0, 4.0)
41 print("repr(v1),", repr(v1))42 v2 =eval(repr(v1))43 print(v1 ==v2)44 #True
45 print(v1)46 #(3.0, 4.0)
47 octets =bytes(v1)48 print(octets)49 #b'd\\x00\\x00\\x00\\x00\\x00\\x00\\x08@\\x00\\x00\\x00\\x00\\x00\\x00\\x10@'
50 print(abs(v1))51 #5.0
52 print(bool(v1), bool(Vector2d(0, 0)))53 #(True, False)
備選構造方法
我們可以Vector2d實例轉換成字節序列了,那么也應該提供一個方法轉換回來。array.array中有個frombytes方法
1 classVector2d:2 """
3 自定義一個二維向量類4 """
5 typecode = 'd'
6 def __init__(self, x, y):7 self.x =x8 self.y =y9
10 def __iter__(self):11 return (i for i in(self.x, self.y))12
13 def __repr__(self):14 return '{}({!r}, {!r})'.format(type(self).__name__, self.x, self.y)15
16 def __str__(self):17 return str(tuple(self)) #已經實現了__iter__方法,self實例是可迭代對象
18
19 def __eq__(self, other):20 return tuple(self) ==tuple(other)21
22 def __abs__(self):23 returnmath.hypot(self.x, self.y)24
25 def __bool__(self):26 returnbool(abs(self))27
28 def __bytes__(self):29 return bytes([ord(self.typecode)])+bytes(array(self.typecode, self))30
31 @classmethod32 deffrombytes(cls, octets):33 typecode =chr(octets[0])34 memv = memoryview(octets[1:]).cast(typecode)35 return cls(*memv)36
37 v1 = Vector2d(3, 4)38 print(v1.x, v1.y)39 #3.0 4.0
40 x, y =v141 print(x, y)42 #(3.0, 4.0)
43 print(v1)44 #Vector2d(3.0, 4.0)
45 print("repr(v1),", repr(v1))46 v2 =eval(repr(v1))47 print(v1 ==v2)48 #True
49 print(v1)50 #(3.0, 4.0)
51 octets =bytes(v1)52 print(octets)53 #b'd\\x00\\x00\\x00\\x00\\x00\\x00\\x08@\\x00\\x00\\x00\\x00\\x00\\x00\\x10@'
54 print(abs(v1))55 #5.0
56 print(bool(v1), bool(Vector2d(0, 0)))57 #(True, False)
58 v2 =Vector2d.frombytes(octets)59 print(v2)
classmethod和staticmethod
classmethod定義了操作類的方法而不是實例。classmethod改變了調用方法的方式,第一個參數是類本身,而不是實例。classmethod最常見的用途就是定義備選函數構造方法,如上面的frombytes,按照約定,類方法的第一個參數名為cls。(實際上,怎么命名都可以)
staticmethod也會改變方法的調用方式,但是第一個蠶食不是特殊的值,事實上,靜態方法就是普通的函數,只是碰巧在類的定義體中。
格式化顯示
1 classVector2d:2 typecode = 'd'
3 def __init__(self, x, y):4 self.x, self.y =x, y5 def __iter__(self):6 return (i for i in(self.x, self.y))7 def __repr__(self):8 return '{}({!r}, {!r})' %(type(self).__name__, self.x, self.y)9 def __str__(self):10 returnstr(tuple(self))11 def __bytes__(self):12 return (bytes([ord(self.typecode)]) +
13 bytes(array(self.typecode, self)))14 def __eq__(self, other):15 return tuple(self)==tuple(other)16 def __abs__(self):17 returnmath.hypot(self.x, self.y)18 def __bool__(self):19 returnbool(abs(self))20 @classmethod21 deffrombytes(cls, octets):22 typecode =chr(octets[0])23 memv = memoryview(octets[1:]).cast(typecode)24 return cls(*memv)25 def __format__(self, fmt=""):26 if fmt.endswith('p'):27 polar =(abs(self), self.angle())28 s =polar29 outer_fmt = '<{}, {}>'
30 else:31 s =self32 outer_fmt = '({}, {})'
33 components = (format(c, fmt.rstrip('p')) for c ins)34 return outer_fmt.format(*components)35 defangle(self):36 returnmath.atan2(self.y, self.x)37 v1 = Vector2d(3, 4)38 print(format(v1, '.2f'))39 print(format(v1, '.4e'))40 print(format(v1, '.3ep'))
使用__slots__類屬性節省空間
python在各個實例中的__dict__字典里存儲實例屬性,通過之前的學習,我們知道dict字典這種結構是典型的空間換時間,會消耗掉大量的內存,如果要處理數百萬的實例,通過__slots__屬性,就能節省大量內存,方法是讓解釋器在類似元組的結構中存儲實例屬性,而不是字典。(超類的__slots__屬性,對子類沒有效果)
1 classVector2d:2 __slots__ = ('_x', '_y')3 ...
ps:如果要處理數百萬個數值對象,應該使用numpy。
__slots__設計之初是為了節省內存,但是也帶來了一個副作用,那就是不能再為實例添加__slots__之外的屬性。
需要明確的是:使用__slots__的充分理由應該是為了節省內存,而不是限制實例屬性,__slots__是用于優化的,而非約束程序員。
總結
以上是生活随笔為你收集整理的python中forward_符合python风格的对象的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 股票绿色的是涨了还是跌了
- 下一篇: 老三板股票哪里查询