掌握python的dataclass,让你的代码更简洁优雅!

在这里插入图片描述

"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全套学习资料,希望能帮到那些不满现状,想提升自己却又没有方向的朋友,也可以和我一起来学习交流呀。

包含编程资料、学习路线图、源代码、软件安装包等!【[点击这里]】领取!

  • ① Python所有方向的学习路线图,清楚各个方向要学什么东西
  • ② 100多节Python课程视频,涵盖必备基础、爬虫和数据分析
  • ③ 100多个Python实战案例,学习不再是只会理论
  • ④ 华为出品独家Python漫画教程,手机也能学习

可以扫描下方二维码领取【保证100%免费

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值