全文共2607字,預計學習時長14分鐘
圖源:unsplash
數據類適用於Python3.7或更高版本,它不僅可以用作數據容器,還可以編寫樣板代碼,簡化創建類的過程。
創建第一個數據類
創建一個數據類,該數據類表示三維座標系中的一個點。
@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函數的參數可以自定義字段和數據類。自定義過程將用例子進行說明,本文結尾也會給出字段和數據類的所有參數。
圖源: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之類的方法啦。
圖源: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異常。
圖源:unsplash
字段參數
· init:如果爲True,則此字段包含在生成的init方法中。(默認爲True)
· repr:如果爲True,則此字段包含在生成的repr方法中。(默認爲True)
· compare:如果爲True,則此字段包含在生成的比較和相等方法中。(默認爲True)
· hash:如果爲True,則此字段包含在生成的hash方法中。(默認爲None)
· default:這是此字段的默認值(如果提供)。
· default_factory:當該字段需要默認值時將調用該參數,此時該參數必須爲零階可調用參數對象。
· metadata:可以是映射,也可以爲空,爲空則將其視爲空字典。
以上就是關於Python中數據類的簡要介紹,你掌握了嗎?
一起分享AI學習與發展的乾貨
歡迎關注全平臺AI垂類自媒體 “讀芯術”
(添加小編微信:dxsxbb,加入讀者圈,一起討論最新鮮的人工智能科技哦~)