成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Python如何設計面向對象的類(上)

開發 后端
Python是一門高級語言,支持面向對象設計,如何設計一個符合Python風格的面向對象的類,是一個比較復雜的問題,本文提供一個參考,表達一種思路,探究一層原理。

 [[408922]]

本文轉載自微信公眾號「dongfanger」,作者dongfanger。轉載本文請聯系dongfanger公眾號。

Python是一門高級語言,支持面向對象設計,如何設計一個符合Python風格的面向對象的類,是一個比較復雜的問題,本文提供一個參考,表達一種思路,探究一層原理。

目標

期望實現的類具有以下基本行為:

  • __repr__ 為repr()提供支持,返回便于開發者理解的對象字符串表示形式。
  • __str__ 為str()提供支持,返回便于用戶理解的對象字符串表示形式。
  • __bytes__ 為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 = v1  # 支持拆包 
  5. >>> x, y 
  6. (3.0, 4.0) 
  7. >>> v1  # 支持repr 
  8. Vector2d(3.0, 4.0) 
  9. >>> v1_clone = eval(repr(v1))  # 驗證repr描述準確 
  10. >>> v1 == v1_clone  # 支持==運算符 
  11. True 
  12. >>> print(v1)  # 支持str 
  13. (3.0, 4.0) 
  14. >>> octets = bytes(v1)  # 支持bytes 
  15. >>> octets 
  16. b'd\\x00\\x00\\x00\\x00\\x00\\x00\\x08@\\x00\\x00\\x00\\x00\\x00\\x00\\x10@' 
  17. >>> abs(v1)  # 實現__abs__ 
  18. 5.0 
  19. >>> bool(v1), bool(Vector2d(0, 0))  # 實現__bool__ 
  20. (TrueFalse

基本實現

代碼與解析如下:

  1. from array import array 
  2. import math 
  3.  
  4.  
  5. class Vector2d: 
  6.     # Vector2d實例和二進制之間轉換時使用 
  7.     typecode = 'd'   
  8.  
  9.     def __init__(self, x, y): 
  10.         # 轉換為浮點數 
  11.         self.x = float(x)     
  12.         self.y = float(y) 
  13.  
  14.     def __iter__(self): 
  15.         # 生成器表達式,把Vector2d實例變成可迭代對象,這樣才能拆包 
  16.         return (i for i in (self.x, self.y))   
  17.  
  18.     def __repr__(self): 
  19.         class_name = type(self).__name__ 
  20.         # {!r}是個萬能的格式符 
  21.         # *self是拆包,*表示所有元素 
  22.         return '{}({!r}, {!r})'.format(class_name, *self) 
  23.  
  24.     def __str__(self): 
  25.         # Vector2d實例是可迭代對象,可以得到一個元組,并str 
  26.         return str(tuple(self)) 
  27.  
  28.     def __bytes__(self): 
  29.         # 轉換為二進制 
  30.         return (bytes([ord(self.typecode)]) +   
  31.                 bytes(array(self.typecode, self)))   
  32.  
  33.     def __eq__(self, other): 
  34.         # 比較相等 
  35.         return tuple(self) == tuple(other)   
  36.  
  37.     def __abs__(self): 
  38.         # 向量的模是直角三角形的斜邊長 
  39.         return math.hypot(self.x, self.y)  
  40.  
  41.     def __bool__(self): 
  42.         # 0.0是False,非零值是True 
  43.         return bool(abs(self))   
  44.      
  45.     @classmethod 
  46.     def frombytes(cls, octets):  # classmethod不傳self傳cls 
  47.         typecode = chr(octets[0]) 
  48.         memv = memoryview(octets[1:]).cast(typecode) 
  49.         return cls(*memv)  # 拆包后得到構造方法所需的一對參數 

代碼最后用到了@classmethod裝飾器,它容易跟@staticmethod混淆。

@classmethod的用法是:定義操作類,而不是操作實例的方法。常用來定義備選構造方法。

@staticmethod其實就是個普通函數,只不過剛好放在了類的定義體里。實際定義在類中或模塊中都可以。

格式化顯示

代碼與解析如下:

  1. def angle(self): 
  2.     return math.atan2(self.y, self.x) 
  3.  
  4.  
  5. def __format__(self, fmt_spec=''): 
  6.     if fmt_spec.endswith('p'):  # 以'p'結尾,使用極坐標 
  7.         fmt_spec = fmt_spec[:-1] 
  8.         coords = (abs(self), self.angle())  # 計算極坐標(magnitude, angle) 
  9.         outer_fmt = '<{}, {}>'  # 尖括號 
  10.     else
  11.         coords = self  # 不以'p'結尾,構建直角坐標(x, y) 
  12.         outer_fmt = '({}, {})'  # 圓括號 
  13.     components = (format(c, fmt_spec) for c in coords)  # 使用內置format函數格式化字符串 
  14.     return outer_fmt.format(*components)  # 拆包后代入外層格式 

它實現了以下效果:

直角坐標:

  1. >>> format(v1) 
  2. '(3.0, 4.0)' 
  3. >>> format(v1, '.2f'
  4. '(3.00, 4.00)' 
  5. >>> format(v1, '.3e'
  6. '(3.000e+00, 4.000e+00)' 

極坐標:

  1. >>> format(Vector2d(1, 1), 'p')  # doctest:+ELLIPSIS 
  2. '<1.414213..., 0.785398...>' 
  3. >>> format(Vector2d(1, 1), '.3ep'
  4. '<1.414e+00, 7.854e-01>' 
  5. >>> format(Vector2d(1, 1), '0.5fp'
  6. '<1.41421, 0.78540>' 

可散列的

實現__hash__特殊方法能讓Vector2d變成可散列的,不過在這之前需要先讓屬性不可變,代碼如下:

  1. def __init__(self, x, y): 
  2.     # 雙下劃線前綴,變成私有的 
  3.     self.__x = float(x) 
  4.     self.__y = float(y) 
  5.  
  6. @property  # 標記為特性 
  7. def x(self): 
  8.     return self.__x 
  9.  
  10. @property 
  11. def y(self): 
  12.     return self.__y 

這樣x和y就只讀不可寫了。

屬性名字的雙下劃線前綴叫做名稱改寫(name mangling),相當于_Vector2d__x和_Vector2d__y,能避免被子類覆蓋。

然后使用位運算符異或混合x和y的散列值:

  1. def __hash__(self): 
  2.     return hash(self.x) ^ hash(self.y) 

節省內存

Python默認會把實例屬性存儲在__dict__字典里,字典的底層是散列表,數據量大了以后會消耗大量內存(以空間換時間)。通過__slots__類屬性,能把實例屬性存儲到元組里,大大節省內存空間。

示例:

  1. class Vector2d: 
  2.     __slots__ = ('__x''__y'
  3.  
  4.     typecode = 'd' 

有幾點需要注意:

必須把所有屬性都定義到__slots__元組中。

子類也必須定義__slots__。

實例如果要支持弱引用,需要把__weakref也加入__slots__。

覆蓋類屬性

實例覆蓋

Python有個很獨特的特性:類屬性可用于為實例屬性提供默認值。實例代碼中的typecode就能直接被self.typecode拿到。但是,如果為不存在的實例屬性賦值,會新建實例屬性,類屬性不會受到影響,self.typecode拿到的是實例屬性的typecode。

示例:

  1. >>> v1 = Vector2d(1, 2) 
  2. >>> v1.typecode = 'f' 
  3. >>> v1.typecode 
  4. 'f' 
  5. >>> Vector2d.typecode 
  6. 'd' 

子類覆蓋

類屬性是公開的,所以可以直接通過Vector2d.typecode = 'f'進行修改。但是更符合Python風格的做法是定義子類:

  1. class ShortVector2d(Vector2d): 
  2.     typecode = 'f' 

Django基于類的視圖大量使用了這個技術。

小結

本文先介紹了如何實現特殊方法來設計一個Python風格的類,然后分別實現了格式化顯示與可散列對象,使用__slots__能為類節省內存,最后討論了類屬性覆蓋技術,子類覆蓋是Django基于類的視圖大量用到的技術。

參考資料:

《流暢的Python》第9章 符合Python風格的對象

https://www.jianshu.com/p/7fc0a177fd1f

 

責任編輯:武曉燕 來源: dongfanger
相關推薦

2021-07-16 10:23:47

Python設計對象

2010-02-02 13:15:26

Python類

2009-01-16 08:52:26

面向對象OOP編程

2013-04-17 10:46:54

面向對象

2012-03-14 10:48:05

C#

2023-09-27 23:28:28

Python編程

2012-06-07 10:11:01

面向對象設計原則Java

2024-05-10 09:28:57

Python面向對象代碼

2012-12-25 10:51:39

IBMdW

2023-11-02 07:55:31

Python對象編程

2013-06-07 11:31:36

面向對象設計模式

2010-03-18 13:43:40

python面向對象

2011-07-05 16:05:43

面向對象編程

2010-06-10 10:03:42

UML面向對象

2022-04-01 10:27:04

面向對象串口協議代碼

2010-07-08 10:47:42

UML面向對象

2011-07-05 15:22:04

程序設計

2011-07-05 15:59:57

面向對象編程

2016-03-11 09:46:26

面向對象設計無狀態類

2016-10-11 15:42:08

點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 一区二区三区在线 | 日韩av一区在线观看 | 黄色欧美在线 | 久久久久久一区 | 国产视频一区二区在线观看 | 国产高清在线精品 | 国产欧美在线一区二区 | 中文一区| 久久久久久久久久久高潮一区二区 | 91精品国产91久久久久久吃药 | 中文字幕第一页在线 | 亚洲精品视| 天堂视频中文在线 | 99精品久久久久久中文字幕 | 国产午夜精品一区二区三区在线观看 | 天天插天天操 | 精品一二区 | 日韩成人免费在线视频 | 97日韩精品 | 亚洲精品久久久久中文字幕欢迎你 | 国产日韩欧美二区 | 国产传媒在线观看 | 97国产精品视频人人做人人爱 | 午夜免费视频 | 色免费看| 亚洲日本一区二区 | 精品视频一区二区在线观看 | 国产一区二区三区色淫影院 | 欧美一级视频在线观看 | 天天操操| 精品国产乱码久久久久久闺蜜 | 亚洲欧美国产视频 | 综合久久99 | 日韩欧美网 | 欧美成人免费在线视频 | 欧美日韩久久精品 | 亚洲福利精品 | 老妇激情毛片免费 | 中文字幕一区在线观看视频 | 日韩毛片网 | 亚洲欧美一区二区三区视频 |