一文帶你走進Python中的數據類

全文共2607字,預計學習時長14分鐘

 

一文帶你走進Python中的數據類

圖源:unsplash

 

數據類適用於Python3.7或更高版本,它不僅可以用作數據容器,還可以編寫樣板代碼,簡化創建類的過程。

 

一文帶你走進Python中的數據類

 

創建第一個數據類

 

創建一個數據類,該數據類表示三維座標系中的一個點。

 

@dataclass裝飾器用於創建數據類。x,y和z是數據類中的字段。注意要使用類型註釋來指定字段的數據類型,但是類型註釋不是靜態類型聲明,這意味着仍然可以爲x,y或z字段傳遞除int之外的任何數據類型。

 

from dataclasses import dataclass
             @dataclass
           classCoordinate:
              x: int
              y: int
              z: int

 

默認情況下,數據類附帶有init、repr和 eq方法,因此我們不必自己實現。但是如果init、repr和eq沒有在Coordinate類中實現,有了數據類,我們仍然可以使用這些方法,這樣非常節省時間。

 

from dataclasses import dataclass
             @dataclass
           classCoordinate:
              x: int
              y: int
              z: int
             a =Coordinate(4, 5, 3)
           print(a)  # output: Coordinate(x=4, y=5, z=3)

 

字段的默認值

 

編碼者可以爲字段分配默認值。如下所示,數據類中的pi字段被分配了默認值:

 

from dataclasses import dataclass
             @dataclass
           classCircleArea:
              r: int
              pi: float =3.14
                 @property
              defarea(self):
                   return self.pi * (self.r **2)
             a =CircleArea(2)
           print(repr(a))  # output: CircleArea(r=2, pi=3.14)
           print(a.area)  # output: 12.56

 

自定義字段和數據類

 

設置dataclass裝飾器或field函數的參數可以自定義字段和數據類。自定義過程將用例子進行說明,本文結尾也會給出字段和數據類的所有參數。

 

一文帶你走進Python中的數據類

圖源:unsplash

 

數據類可變還是不可變?

 

默認情況下,數據類是可變的,這意味着可以爲字段分配值。但我們可以通過將frozen參數設置爲True來使其不可變

 

可變示例:

 

from dataclasses import dataclass
             @dataclass
           classCircleArea:
              r: int
              pi: float =3.14
                 @property
              defarea(self):
                   return self.pi * (self.r **2)
             a =CircleArea(2)
           a.r =5
           print(repr(a))  # output: CircleArea(r=5, pi=3.14)
           print(a.area)  # output: 78.5

 

不可變示例:

 

設置frozen爲 True,將無法再爲字段分配值。在下面的示例中可以看到異常輸出。

 

from dataclasses import dataclass
             @dataclass(frozen=True)
           classCircleArea:
              r: int
              pi: float =3.14
                 @property
              defarea(self):
                   return self.pi * (self.r **2)
             a =CircleArea(2)
           a.r =5
           # Exceptionoccurred: dataclasses.FrozenInstanceError:
           # cannot assign tofield 'r'

 

比較數據類

 

假設要創建一個表示Vector的數據類並進行比較,你會怎麼做?當然需要使用諸如lt或gt之類的方法啦。

 

一文帶你走進Python中的數據類

 

圖源:unsplash

 

默認情況下,數據類的order參數爲 False。將其設置爲True,會自動爲數據類生成 lt、le、gt和ge方法。因此,可以按順序比較對象,就像它們是其字段的元組一樣。

 

研究下面的示例:將order設置爲True就可以比較v2和v1。這裏存在一個邏輯比較的問題。當v2> v1時,它將比較這兩個向量,例如(8,15)>(7,20)。因此,v2> v1的輸出將爲True。

 

回想一下,元組比較是逐個按照順序進行的。首先將8和7進行比較,結果爲True,那麼比較結果就爲True。如果它們相等,則比較15> 20,結果爲False:

 

from dataclasses import dataclass,field
   
                       @dataclass(order=True)
           classVector:
              x: int
              y: int
             v1 =Vector(8, 15)
           v2 =Vector(7, 20)
           print(v2 > v1)

 

顯然這種比較沒有任何意義。筆者最初想通過向量的大小來比較它們。但問題是,不可能在創建每個實例時,都要自己計算Vector的大小。

 

在這種情況下,field函數和post_init方法更有用。field函數能自定義magnitude字段。而post_init方法則會確定初始化後該矢量的大小。

 

還可以使用數據類中的field函數來自定義magnitude字段。通過將init設置爲False,基本可以不需要init方法中的magnitude參數。因爲初始化後才使用post_init方法來確定其值:

 

from dataclasses import dataclass, field
             @dataclass(order=True)
           classVector:
              magnitude: float =field(init=False)
              x: int
              y: int
                 def__post_init__(self):
                   self.magnitude = (self.x **2+ self.y **2) **0.5
             v1 =Vector(9, 12)
           print(v1)  # output: Vector(magnitude=15.0, x=9,y=12)
           v2 =Vector(8, 15)
           print(v2)  # output: Vector(magnitude=17.0, x=8,y=15)
           print(v2 > v1)  # output: True

 

將數據類轉換爲字典或元組

 

從元組或字典中獲取數據類的屬性,只需要從數據類中導入asdict和astuple函數:

 

from dataclasses import dataclass,asdict, astuple
             @dataclass
           classVector:
              x: int
              y: int
              z: int
             v =Vector(4, 5, 7)
           print(asdict(v))  # output: {'x': 4, 'y': 5, 'z': 7}
           print(astuple(v))  # output: (4, 5, 7)

 

繼承

 

可以像Python中的普通類一樣對數據類進行子類化:

 

from dataclasses import dataclass
             @dataclass
           classEmployee:
              name: str
              lang: str
             @dataclass
           classDeveloper(Employee):
              salary: int
             Halil=Developer('Halil', 'Python', 5000)
           print(Halil)  # Output: Developer(name='Halil',lang='Python', salary=5000)

 

使用繼承時經常會忽視一點:默認情況下,當將lang字段設置爲Python時,必須爲lang字段之後的字段提供默認值:

 

from dataclasses import dataclass
             @dataclass
           classEmployee:
              name: str
              lang: str ='Python'
             @dataclass
           classDeveloper(Employee):
              salary: int
             Halil=Developer('Halil', 'Python', 5000)
           # Output:TypeError: non-default argument 'salary' follows default argument

 

原因在於init方法。回想一下,具有默認值的參數應該位於沒有默認值的參數之後:

 

def__init__(name: str,lang: str ='Python', salary: int):

...

通過對sanlary字段設置默認值來對其進行修復:

 

from dataclasses import dataclass
             @dataclass
           classEmployee:
              name: str
              lang: str ='Python'
             @dataclass
           classDeveloper(Employee):
              salary: int =0
             Halil=Developer('Halil', 'Python', 5000)
           print(Halil)  # output: Developer(name='Halil',lang='Python', salary=5000)

 

slots的好處

 

默認情況下,屬性存儲在字典中。使用slots可以更快地訪問屬性並且內存佔用更少。

 

from dataclasses import dataclass
             @dataclass
           classEmployee:
              name: str
              lang: str
             Halil=Employee('Halil', 'Python')
           print(Halil.__dict__)  # name': 'Halil', 'lang': 'Python'}

 

slots內存佔用更小,訪問屬性更快。

 

from dataclasses import dataclass
             @dataclass
           classEmployee:
              __slots__ = ('name', 'lang')
              name: str
              lang: str
             Halil=Employee('Halil', 'Python')

 

數據類參數

 

剛剛我們更改了數據類裝飾器中的某些參數,以自定義數據類。以下是參數列表:

 

· nit:如果爲True,則在數據類中生成init方法。(默認爲True)

· repr:如果爲True,則在數據類中生成repr方法。(默認爲True)

· eq:如果爲True,則在數據類中生成eq方法。(默認爲True)

· order:如果爲True,則在數據類中生成lt,le,gt和ge方法。(默認爲False)

· unsafe_hash:如果爲True,則在數據類中生成hash方法。(默認爲False)

· frozen:如果爲True,則不能給字段分配值。(默認爲False。)

 

注意,如果order爲True,eq必須也爲True,否則將引發ValueError異常。

 

一文帶你走進Python中的數據類

 

圖源:unsplash

 

字段參數

 

· init:如果爲True,則此字段包含在生成的init方法中。(默認爲True)

· repr:如果爲True,則此字段包含在生成的repr方法中。(默認爲True)

· compare:如果爲True,則此字段包含在生成的比較和相等方法中。(默認爲True)

· hash:如果爲True,則此字段包含在生成的hash方法中。(默認爲None)

· default:這是此字段的默認值(如果提供)。

· default_factory:當該字段需要默認值時將調用該參數,此時該參數必須爲零階可調用參數對象。

· metadata:可以是映射,也可以爲空,爲空則將其視爲空字典。

 

以上就是關於Python中數據類的簡要介紹,你掌握了嗎?

 

一文帶你走進Python中的數據類

 

一起分享AI學習與發展的乾貨
歡迎關注全平臺AI垂類自媒體 “讀芯術”

(添加小編微信:dxsxbb,加入讀者圈,一起討論最新鮮的人工智能科技哦~)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章