亲宝软件园·资讯

展开

Python dataclass库

A-L-Kun 人气:0

dataclass语法

一、 简介

官方文档的地址为:https://docs.python.org/3.9/library/dataclasses.html

dataclass的定义位于PEP-557,根据定义一个dataclass是指“一个带有默认值的可变的namedtuple”,广义的定义就是有一个类,它的属性均可公开访问,可以带有默认值并能被修改,而且类中含有与这些属性相关的类方法,那么这个类就可以称为dataclass,再通俗点讲,dataclass就是一个含有数据及操作数据方法的容器。

乍一看可能会觉得这个概念不就是普通的class么,然而还是有几处不同:

我们来创建一个实例:

from dataclasses import dataclass
@dataclass
class InventoryItem:
    """Class for keeping track of an item in inventory."""
    name: str
    unit_price: float
    quantity_on_hand: int = 0
    def total_cost(self) -> float:
        return self.unit_price * self.quantity_on_hand

同时,我们也可以添加__init__方法:

def __init__(self, name: str, unit_price: float, quantity_on_hand: int = 0):
    self.name = name
    self.unit_price = unit_price
    self.quantity_on_hand = quantity_on_hand

同时使用dataclass也有一些好处,它比namedtuple更灵活。同时因为它是一个常规的类,所以你可以享受继承带来的便利。

二、 装饰器参数

参数为dataclass()

@dataclass
class C:
    ...
@dataclass()
class C:
    ...
@dataclass(init=True, repr=True, eq=True, order=False, unsafe_hash=False, frozen=False)
class C:
   ...

三、 数据属性

1、 参数

参数为field()

2、 使用示例

@dataclass
class C:
    x: int
    y: int = field(repr=False)
    z: int = field(repr=False, default=10)
    t: int = 20

3、 注意事项

init参数如果设置为False,表示不为这个field生成初始化操作,dataclass提供了hook——__post_init__供我们利用这一特性:

@dataclass
class C:
    a: int
    b: int
    c: int = field(init=False)
 
    def __post_init__(self):
        self.c = self.a + self.b

__post_init____init__后被调用,我们可以在这里初始化那些需要前置条件的field。

repr参数表示该field是否被包含进repr的输出,compare和hash参数表示field是否参与比较和计算hash值。metadata不被dataclass自身使用,通常让第三方组件从中获取某些元信息时才使用,所以我们不需要使用这一参数。

如果指定一个field的类型注解为dataclasses.InitVar,那么这个field将只会在初始化过程中(__init____post_init__)可以被使用,当初始化完成后访问该field会返回一个dataclasses.Field对象而不是field原本的值,也就是该field不再是一个可访问的数据对象。举个例子,比如一个由数据库对象,它只需要在初始化的过程中被访问:

@dataclass
class C:
    i: int
    j: int = None
    database: InitVar[DatabaseType] = None
 
    def __post_init__(self, database):
        if self.j is None and database is not None:
            self.j = database.lookup('j')
c = C(10, database=my_database)

四、 其他

1、 常用函数

dataclasses模块中提供了一些常用函数供我们处理数据类。

使用dataclasses.asdictdataclasses.astuple我们可以把数据类实例中的数据转换成字典或者元组:

>>> from dataclasses import asdict, astuple
>>> asdict(C())
{'name': 'python', 'strong_type': True, 'static_type': False, 'age': 28}
>>> astuple(C())
('python', True, False, 28)

使用dataclasses.is_dataclass可以判断一个类或实例对象是否是数据类

2、 继承

dataclass装饰器会检查当前class的所有基类,如果发现一个dataclass,就会把它的字段按顺序添加进当前的class,随后再处理当前class的field。所有生成的方法也将按照这一过程处理,因此如果子类中的field与基类同名,那么子类将会无条件覆盖基类。子类将会根据所有的field重新生成一个构造函数,并在其中初始化基类。

看个例子:

@dataclass
class Base:
    x: float = 25.0
    y: int = 0
 
@dataclass
class C(Base):
    z: int = 10
    x: int = 15
 
>>> C()
C(x=15, y=0, z=10)

C中的x则覆盖了Base中的定义

3、 总结

合理使用dataclass将会大大减轻开发中的负担,将我们从大量的重复劳动中解放出来,这既是dataclass的魅力,不过魅力的背后也总是有陷阱相伴,最后我想提几点注意事项:

只要避开这些陷阱,dataclass一定能成为提高生产力的利器。

加载全部内容

相关教程
猜你喜欢
用户评论