python 自定义类(特殊方法)
生活随笔
收集整理的這篇文章主要介紹了
python 自定义类(特殊方法)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
文章目錄
- 1. 對象表示形式
- 2. 可散列的類
- 3. 私有屬性的利弊
- 4. `__slots__` 類屬性節省空間
- 5. 覆蓋類屬性
learn from 《流暢的python》
from array import array import mathclass Vector2D:typecode = 'd' # 類屬性def __init__(self, x, y):self.x = float(x)self.y = float(y)@classmethod # 裝飾器, 函數不需要傳入 self 參數,需要cls 傳入類本身# classmethod 最常見的用途是 定義備選構造方法# @staticmethod 就是定義在類中的普通函數def frombytes(cls, octets):typecode = chr(octets[0])memv = memoryview(octets[1:]).cast(typecode)return cls(*memv) # 構造類對象@staticmethoddef hello():print("hello world!")def __iter__(self): # 可迭代對象,才能拆包 x,y = my_vectorreturn (i for i in (self.x, self.y)) # 生成器表達式def __repr__(self):class_name = type(self).__name__return '{}({!r},{!r})'.format(class_name, *self)# {!r} 獲取 *self 的分量,可迭代對象def __str__(self):return str(tuple(self)) # 從可迭代對象生成元組def __bytes__(self):return (bytes([ord(self.typecode)]) + bytes(array(self.typecode, self)))def __eq__(self, other):return tuple(self) == tuple(other)def __abs__(self):return math.hypot(self.x, self.y)def __bool__(self):return bool(abs(self))1. 對象表示形式
- repr() 返回便于 開發者 理解的對象字符串形式,須實現__repr()__
- str() 返回便于 用戶 理解的對象字符串形式,須實現__str()__
- __format()__ 會被內置的 format(), str.format() 調用
https://docs.python.org/3/library/string.html#formatspec
v1 = Vector2D(315687,4) print("test str {0.x:5.3e}".format(v1)) # test str 3.157e+05{ 變量 :格式說明符 } 包含兩部分
>>> format(8, 'b') # 二進制 '1000' >>> format(1/3, '.2%') # %百分比 '33.33%'- 如果類沒有定義 __format__ 方法,從 object 繼承的方法會返回 str(my_object),調用 __str__()
為了解決該問題,在類中添加方法:
def __format__(self, fmt_spec=""):components = (format(c, fmt_spec) for c in self)# 使用內置的 format 把格式應用到各個分量上,構成一個可迭代的字符串return "({}, {})".format(*components) # 格式化字符串 print(format(v1, '.3f')) # (315687.000, 4.000)- 自定義極坐標表示
2. 可散列的類
hash(v1) # TypeError: unhashable type: 'Vector2D'為了可以散列,需要實現__hash__(), __eq__()
def __init__(self, x, y):self.__x = float(x)self.__y = float(y)@propertydef x(self):return self.__x@property # @property 裝飾器把讀值方法標記為特性def y(self):return self.__y v1.__x = 100 # 值不可以變更 print(v1) # (315687.0, 4.0) # v1.x = 100 # AttributeError: can't set attribute- 添加 __hash__()
3. 私有屬性的利弊
- 如果子類跟父類有相同的屬性,子類會覆蓋父類
- 以 __ or _開頭的屬性將會被存在 實例的 __dict__ 屬性內,且加上前綴 _類名
名稱改寫是一種安全措施,不能保證萬無一失:它的目的是避免意外訪問,不能防止故意做錯事
Python 解釋器不會對使用 單個下劃線 的屬性名做特殊處理,不過這是很多 Python 程序員嚴格遵守的約定,他們不會在類外部訪問這種屬性。
print(v1._Vector2D__x) # 315687.0 v1._Vector2D__x = 100 print(v1._Vector2D__x) # 100 print(v1) # (100., 4.0)并不能真正的實現 私有和不可變
4. __slots__ 類屬性節省空間
class Vector2d: __slots__ = ('__x', '__y')等號右側可以是可迭代的對象,里面存儲所有實例屬性的名稱的字符串,從而避免使用消耗內存的 __dict__ 屬性
- 在類中定義 __slots__ 屬性之后,實例不能再有 __slots__ 中所列名稱之外的其他屬性
- 為了 讓對象支持弱引用,必須有 __weakref__屬性。用戶定義的類中 默認就有 __weakref__ 屬性。
可是,如果類中定義了 __slots__ 屬性,而且想把實例作為 弱引用 的目標,那么要把 __weakref__ 添加到 __slots__ 中 - 一般不要把 __dict__ 加入到 __slots__ 中
- 每個子類都要定義 __slots__ 屬性,因為解釋器會忽略繼承的 __slots__ 屬性
5. 覆蓋類屬性
print(v1.typecode) # d print(v2.typecode) # d print(bytes(v1)) # b'd\x00\x00\x00\x00\x00\x00Y@\x00\x00\x00\x00\x00\x00\x10@' print(Vector2D.typecode) # dv1.typecode = 'f' print(v1.typecode) # f print(bytes(v1)) # b'f\x00\x00\xc8B\x00\x00\x80@' print(Vector2D.typecode) # d v1.typecode = 'd' print(v1.typecode) # dVector2D.typecode = 'f' print(Vector2D.typecode) # f print(v1.typecode) # d print(v2.typecode) # f- typecode 是類屬性,一旦實例對象賦值 typecode后,實際是創建了新的實例屬性
- 如果為不存在的 實例屬性 賦值,會 新建 實例屬性,類屬性不受影響,但是實例屬性會遮蓋同名類屬性
還可以訂制類的數據屬性:
class anOtherVec(Vector2D):typecode = 'f' # 只是修改子類的數據類型v4 = anOtherVec(3,4) print(bytes(v4))總結
以上是生活随笔為你收集整理的python 自定义类(特殊方法)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 论文阅读 - Large-scale w
- 下一篇: python 执行完成后,cmd窗口自动