定義
dataclass 是python 3.7新增的一個模塊,適用於存儲數據對象
數據對象特性:
1、存儲數據並代表某種數據類型
2、可以與同一類型的其他對象比較
用法
提供了一個裝飾器dataclass,用於將類轉換爲dataclass
下邊是dataclass帶來的變化,分爲初始化、表示、數據比較、可調用的裝飾、Frozen(不可變)實例、後期初始化處理、繼承
初始化
from dataclasses import dataclass
# 初始化
# 未使用dataclass
class Number:
def __init__(self, val):
self.val = val
one = Number(1)
print(one.val) # 1
# 使用dataclass
# 可以設置默認值val:int = 0
@dataclass
class Number:
val:int
one = Number(1)
print(one.val) # 1
說明:
dataclass帶來的變化:
1、無需定義__init__,然後將值賦給self
2、以更加易讀的方式定義了成員屬性及類型提示
表示
# 表示
# 未使用dataclass
class Number:
def __init__(self, val):
self.val = val
one = Number(1)
print(one) # <__main__.Number object at 0x000000000216C2B0>
# 可在類中定義一個__repr__方法來表示
class Number:
def __init__(self, val):
self.val = val
def __repr__(self):
return str(self.val)
one = Number(1)
print(one) # 1
# 使用dataclass
@dataclass
class Number:
val:int = 0
one = Number(1)
print(one) # Number(val=1)
說明:
dataclass 會自動添加一個 __repr__ 函數,這樣我們就不必手動實現它
數據比較
# 數據比較
# 未使用dataclass
class Number:
def __init__(self, val):
self.val = val
def __eq__(self, other):
return self.val == other.val
def __lt__(self, other):
return self.val < other.val
# 使用dataclass
@dataclass(order = True)
class Number:
val:int = 0
import random
a = [Number(random.randint(1,10)) for _ in range(10)]
print(a) # [Number(val=3), Number(val=5), Number(val=5), Number(val=4), Number(val=1), Number(val=5), Number(val=10), Number(val=8), Number(val=1), Number(val=5)]
sorted_a = sorted(a)
print(sorted_a) # [Number(val=1), Number(val=1), Number(val=3), Number(val=4), Number(val=5), Number(val=5), Number(val=5), Number(val=5), Number(val=8), Number(val=10)]
reverse_sorted_a = sorted(a, reverse= True)
print(reverse_sorted_a) # [Number(val=10), Number(val=8), Number(val=5), Number(val=5), Number(val=5), Number(val=5), Number(val=4), Number(val=3), Number(val=1), Number(val=1)]
說明:
- 不需要定義 __eq__ 和 __lt__ 方法,因爲當 order = True 被調用時,dataclass 裝飾器會自動將它們添加到我們的類定義
- 自動生成的方法屬性順序與你在dataclass類中定義的順序一致
- 內置的sorted函數依賴於比較兩個對象
可調用的裝飾
@dataclass(init=True, repr=True, eq=True, order=False, unsafe_hash=False, frozen=False)
class C:
…
說明:
1.參數
init:默認將生成 __init__ 方法。如果傳入 False,那麼該類將不會有 __init__ 方法。
repr:__repr__ 方法默認生成。如果傳入 False,那麼該類將不會有 __repr__ 方法。
eq:默認將生成 __eq__ 方法。如果傳入 False,那麼 __eq__ 方法將不會被 dataclass 添加,但默認爲 object.__eq__。
order:默認將生成 __gt__、__ge__、__lt__、__le__ 方法。如果傳入 False,則省略它們。
2.可以有選擇性地定義所dunder(雙下劃線方法,即魔法方法)
修改默認生成的函數:@dataclass(repr = False)
Frozen(不可變)實例
# 不可變實例
# 使用dataclass
@dataclass(frozen=True)
class Number:
val:int = 0
one = Number(1)
print(one.val) # 1
# one.val = 2 # 報錯'Number' object attribute 'val' is read-only
說明:
frozen實例不可變的特性可以用來存儲常數、設置
後期初始化處理
# 後期初始化處理
# 未使用 dataclass
import math
class Float:
def __init__(self, val = 0):
self.val = val
self.process()
def process(self):
self.decimal, self.integer = math.modf(self.val)
a = Float(2.2)
print(a.decimal) # 0.20000000000000018
print(a.integer) # 2.0
# 使用 dataclass
import math
@dataclass
class FloatNumber:
val:float = 0.0
def __post_init__(self):
self.decimal, self.integer = math.modf(self.val)
a = FloatNumber(2.2)
print(a.decimal) # 0.20000000000000018
print(a.integer) # 2.0
說明:
__init__方法初始化失去了在變量被賦值之後立即需要的函數調用或處理的靈活性。post_init可以彌補這種場景的缺陷,處理後期初始化操作
繼承
# 繼承
# 父類中定義的屬性將在子類中可用
@dataclass
class Person:
age: int = 0
name: str = '1'
@dataclass
class Student(Person):
grade: int = 0
s = Student(18, "mingliang", 100)
print(s.age)
print(s.name)
print(s.grade)
# 繼承過程中__post_init__的行爲
@dataclass
class A:
a: int
def __post_init__(self):
print('A')
@dataclass
class B(A):
b: int
def __post_init__(self):
print('B')
a = B(1, 2) # B 只有 B的 __post_init__ 被調用
@dataclass
class B(A):
b: int
def __post_init__(self):
super().__post_init__() # 父類的函數可以使用 super 調用
print('B')
a = B(1, 2) # A B
說明:
- 父類中定義的屬性將在子類中可用
- 父類的函數可以使用 super 調用