01
引言
大家好,我是AI算法之道!
Python是我最喜欢的编程语言之一,它向来以其简单性、多功能性和可读性而闻名。
大家好!今天我想与大家分享Python3.7引入的标准库dataclass模块,其主要功能是帮助大家简化数据类的定义过程。
闲话少说,我们直接开始吧!
02
传统类的定义
class CoinTrans:
def __init__(
self,
id: str,
symbol: str,
price: float,
is_success: bool,
addrs: list,
) -> None:
self.id = id
self.symbol = symbol
self.price = price
self.addrs = addrs
self.is_success = is_success
if __name__ == "__main__":
coin_trans = CoinTrans("id01", "BTC/USDT", "71000", True, ["0x1111", "0x2222"])
print(coin_trans)
结果如下:
<__main__.CoinTrans object at 0x0000022A891FADD0>
在这里,我们只打印出了对象的地址,而不是像预期的那样打印每个对象的属性值。
在传统的类中,如果我们想打印可读的结果,就需要自己实现 __str__ 函数。
# Add the following method to the CoinTrans class above.
def __str__(self) -> str:
return f"Transaction Information:{self.id}, {self.symbol}, {self.price}, {self.addrs}, {self.is_success}"
再次运行后,结果如下:
Trade information: id01, BTC/USDT, 71000, ['0x1111', '0x2222'], True
03
使用dataclass定义类
from dataclasses import dataclass
@dataclass
class CoinTrans:
id: str
symbol: str
price: float
is_success: bool
addrs: list
if __name__ == "__main__":
coin_trans = CoinTrans("id01", "BTC/USDT", "71000", True, ["0x1111", "0x2222"])
print(coin_trans)
CoinTrans(id='id01', symbol='BTC/USDT', price='71000', is_success=True, addrs=['0x1111', '0x2222'])
无需__init__,无需__str__,只需用 @dataclass 装饰,就能打印出对象的具体内容。
04
设置默认值
需使用dataclass装饰器来定义类,可以非常简单地设置默认值,您可以在定义属性时直接设置默认值。
例如,例子为:
@dataclass
class CoinTrans:
id: str = "id01"
symbol: str = "BTC/USDT"
price: float = "71000.8"
is_success: bool = True
addrs: list[str] = ["0x1111", "0x2222"]
if __name__ == "__main__":
coin_trans = CoinTrans()
print(coin_trans)
ValueError: mutable default <class 'list'> for field addrs is not allowed: use default_factory
简单地说,其含义是作为可变类型(引用类型,有可能被其他对象无意修改)的列表不能直接用作默认值,而需要使用工厂方法生成。这个问题不适用于字符串、数字和布尔等其他数据类型。
为了解决上述问题,我们只需定义一个函数来生成默认值。
def gen_list():
return ["0x1111", "0x2222"]
class CoinTrans:
id: str = "id01"
symbol: str = "BTC/USDT"
price: float = "71000.8"
is_success: bool = True
addrs: list[str] = field(default_factory=gen_list)
if __name__ == "__main__":
coin_trans = CoinTrans()
print(coin_trans)
再次运行,可以正常执行:
CoinTrans(id='id01', symbol='BTC/USDT', price='71000.8', is_success=True, addrs=['0x1111', '0x2222']
05
隐藏敏感信息
在打印对象信息时,有时我们只打印某些属性的信息,而不想打印敏感信息。例如,对于上述对象,如果不想打印 "is_success "和 "addrs "的信息,可以设置 repr=False。
比如:
@dataclass
class CoinTrans:
id: str = "id01"
symbol: str = "BTC/USDT"
price: float = "71000.8"
is_success: bool = field(default=True, repr=False)
addrs: list[str] = field(default_factory=gen_list, repr=False)
再次运行后显示:
CoinTrans(id='id01', symbol='BTC/USDT', price='71000.8')
06
只读对象
if __name__ == "__main__":
coin_trans = CoinTrans()
print(f"Before modification: {coin_trans}")
coin_trans.symbol = "ETH/USDT"
print(f"after modification: {coin_trans}")
结果如下:
Original: CoinTrans(id='id01', symbol='BTC/USDT', price='71000.8')
Modified: CoinTrans(id='id01', symbol='ETH/USDT', price='71000.8')
设置冻结属性后,看看修改属性值会发生什么:
class CoinTrans:
id: str = "id01"
#... omission ...
再次运行时,会发现修改属性会触发异常。
Before modification: CoinTrans(id='id01', symbol='BTC/USDT', price='71000.8')
Traceback (most recent call last):
File "D:\projects\python\samples\data_classes\main.py", line 66, in <module>
coin_trans.symbol = "ETH/USDT"
^^^^^^^^^^^^^^^^^
File "<string>", line 4, in __setattr__
dataclasses.FrozenInstanceError: cannot assign to field 'symbol'
07
转换为元组或字典
from dataclasses import dataclass, field, astuple, asdict
if __name__ == "__main__":
coin_trans = CoinTrans()
print(astuple(coin_trans))
print(asdict(coin_trans))
('id01', 'BTC/USDT', '71000.8', True, ['0x1111', '0x2222'])
{'id': 'id01', 'symbol': 'BTC/USDT', 'price': '71000.8', 'is_success': True, 'addrs': ['0x1111', '0x2222']}
08
总结
在 Python 中,数据类主要用于存储数据,通常包含对这些数据进行操作的属性和方法。然而,在定义传统数据类时,我们经常需要编写一些重复的代码,如构造函数、属性访问函数和字符串表示法。
dataclass装饰器的出现自动生成了这些常用方法,大大简化了数据类的定义过程。
总之,简化dataclass 的创建和管理过程可以提高开发效率,是数据分析的一种有用工具。
点击上方小卡片关注我
添加个人微信,进专属粉丝群!