日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

python 自定义类(特殊方法)

發布時間:2024/7/5 python 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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() 調用
>>> brl = 1/2.43 >>> brl 0.4115226337448559 >>> format(brl, "0.4f") '0.4115' >>> format(brl, ".4f") '0.4115' >>> "1 BRL = {rate:0.2f} USD".format(rate=brl) '1 BRL = 0.41 USD'

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__()
print(format(v1)) # (315687.0, 4.0) print(format(v1, '.3f')) # TypeError: unsupported format string passed to Vector2D.__format__

為了解決該問題,在類中添加方法:

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)
  • 自定義極坐標表示
def angle(self):return math.atan2(self.y, self.x)def __format__(self, fmt_spec=""):if fmt_spec.endswith('p'): # 以 p 結尾的用極坐標fmt_spec = fmt_spec[:-1]coords = (abs(self), self.angle())outer_fmt = "<{}, {}>"else:coords = selfouter_fmt = "({}, {})"components = (format(c, fmt_spec) for c in coords)return outer_fmt.format(*components) print(format(Vector2D(1, 1), 'p')) print(format(Vector2D(1, 1), '.3ep')) print(format(Vector2D(1, 1), '0.5fp')) print(format(Vector2D(1, 1), '0.2f'))<1.4142135623730951, 0.7853981633974483> <1.414e+00, 7.854e-01> <1.41421, 0.78540> (1.00, 1.00)

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__()
def __hash__(self):return hash(self.x) ^ hash(self.y) v2 = Vector2D(10, 20) v3 = Vector2D(10, 20) print(hash(v1)) # 315683 print(hash(v2)) # 30 print(v2 is v3) # False print(hash(v3)) # 30 print(set([v1, v2, v3])) # {Vector2D(315687.0,4.0), Vector2D(10.0,20.0)}

3. 私有屬性的利弊

  • 如果子類跟父類有相同的屬性,子類會覆蓋父類
  • 以 __ or _開頭的屬性將會被存在 實例的 __dict__ 屬性內,且加上前綴 _類名
print(v1.__dict__) # {'_Vector2D__x': 315687.0, '_Vector2D__y': 4.0, '__x': 100} print(v1._Vector2D__x) # 315687.0

名稱改寫是一種安全措施,不能保證萬無一失:它的目的是避免意外訪問,不能防止故意做錯事

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 自定义类(特殊方法)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。