一文详解python中dataclass的使用技巧
作者:databook
引言
dataclass
是从Python3.7
版本开始,作为标准库中的模块被引入。
随着Python
版本的不断更新,dataclass
也逐步发展和完善,为Python
开发者提供了更加便捷的数据类创建和管理方式。
dataclass
的主要功能在于帮助我们简化数据类的定义过程。
本文总结了几个我平时使用较多dataclass
技巧。
1. 传统的类定义方式
首先,从平时量化分析的场景中简化一个关于 币交易 的类用来演示。
简化之后,这里只保留5个字段,分别是交易ID,交易对,价格,是否成功和参与交易的地址列表。
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
Python
传统定义类的方式,如上通过__init__
函数来初始化对象的各个属性。
通过这个类构造对象并打印:
if __name__ == "__main__": coin_trans = CoinTrans("id01", "BTC/USDT", "71000", True, ["0x1111", "0x2222"]) print(coin_trans)
运行结果:
<__main__.CoinTrans object at 0x0000022A891FADD0>
这里只是打印出对象的地址,并没有按照我们期望的那样打印对象各个属性的值。
传统的类中,我们如果希望打印出可读的结果,需要自己去实现__str__
函数。
# 在上面的 CoinTrans 类中添加下面的方法 def __str__(self) -> str: return f"交易信息:{self.id}, {self.symbol}, {self.price}, {self.addrs}, {self.is_success}"
再次运行,结果如下:
交易信息:id01, BTC/USDT, 71000, ['0x1111', '0x2222'], True
2. dataclass装饰器定义类
下面看看使用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
装饰之后,就可以打印出对象的具体内容。
2.1. 默认值
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)
运行之后发现,在addrs
属性那行会报错:
ValueError: mutable default <class 'list'> for field addrs is not allowed: use default_factory
大概的意思就是,list
作为一种可变的类型(引用类型,会有被其他对象意外修改的风险),不能直接作为默认值,需要用工厂方法来产生默认值。
其他字符串,数值,布尔类型的数据则没有这个问题。
我们只要定义个函数来产生此默认值即可。
def gen_list(): return ["0x1111", "0x2222"] @dataclass 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']
2.2. 隐藏敏感信息
我们打印对象信息的时候,有时执行打印其中几个属性的信息,涉及敏感信息的属性不希望打印出来。
比如,上面的对象,如果不想打印出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')
2.3. 只读对象
数据分析时,大部分下情况下,原始数据读取之后是不能修改的。
这种情况下,我们可以用dataclass
的frozen
属性来设置数据类只读,防止不小心篡改了数据。
未设置frozen
属性之前,可以随意修改对象的属性,比如:
if __name__ == "__main__": coin_trans = CoinTrans() print(f"修改前: {coin_trans}") coin_trans.symbol = "ETH/USDT" print(f"修改后: {coin_trans}")
运行结果:
修改前: CoinTrans(id='id01', symbol='BTC/USDT', price='71000.8')
修改后: CoinTrans(id='id01', symbol='ETH/USDT', price='71000.8')
设置frozen
属性之后,看看修改属性值会怎么样:
@dataclass(frozen=True) class CoinTrans: id: str = "id01" #... 省略 ...
再次运行,会发现修改属性会触发异常。
修改前: 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'
2.4. 转化为元组和字典
最后,dataclasses
模块还提供了两个函数可以很方便的将数据类转换为元组和字典。
这在和其他分析程序交互时非常有用,因为和其他程序交互时,参数一般都用元组或者字典这种简单通用的结构,
而不会直接用自己定义的数据类。
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']}
3. 总结
在Python
中,数据类主要用于存储数据,并通常包含属性和方法来操作这些数据。
然而,在定义数据类时,我们通常需要编写一些重复性的代码,如构造函数、属性访问器和字符串表示等。dataclass
装饰器的出现,使得这些通用方法的生成变得自动化,从而极大地简化了数据类的定义过程。
总的来说,dataclass
通过简化数据类的创建和管理过程,提高了开发效率,是我们在数据分析时的一个非常有用的工具。
以上就是一文详解python中dataclass的使用技巧的详细内容,更多关于python dataclass使用的资料请关注脚本之家其它相关文章!