python中创建一个类,我们需要写__init__方法进行初始化对象操作,需要对对象进一步说明的话,最好写一个__repr方法,这样我们直接输出对象的话,方便理解这个对象是啥。但在python3.7以后的版本中给我们提供了一个更加简单的方式dataclasses

定义

首先我们用常规的方法创建一个类

class User:

    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __repr__(self):
        return f"User-{self.name}"

user = User("Tony", 18)
print(user.name)  # Tony
print(user.age)  # 18
print(user)  # User-Tony

下面使用dataclasses去创建一个类

from dataclasses import dataclass


@dataclass
class User:
    name: str
    age: int

user = User("Tony", 18)
print(user.name)  # Tony
print(user.age)  # 18
print(user)  # User(name="Tony", age=18)

可以看到相对于普通类的写法是不是显得简单很多

默认值

让我们看看如何给设置默认值

from dataclasses import dataclass


@dataclass
class User:
    name: str
    age: int = 18

user_1 = User("Tony")
print(user_1.name)  # Tony
print(user_1.age)  # 18

user_2 = User("Tom", 20)
print(user_2.name)  # Tom
print(user_2.age)  # 20

添加一个方法

from dataclasses import dataclass


@dataclass
class User:
    name: str
    age: int = 18

    def age_difference(self, other):
        return self.age - other.age

user_1 = User("tony", 20)
user_2 = User("tom")
user_1.age_difference(user_2)  # 2

frozen

frozen实例是在初始化对象后无法修改其属性的对象

@dataclass(frozen = True)
class Number:
    val: int = 0
>>> a = Number(1)
>>> a.val
>>> 1
>>> a.val = 2
>>> Traceback (most recent call last):
 File “<stdin>”, line 1, in <module>
 File “<string>”, line 3, in __setattr__
dataclasses.FrozenInstanceError: cannot assign to field ‘val’

后期初始化处理

有了 dataclass,需要定义一个 __init__ 方法来将变量赋给 self 这种初始化操作已经得到了处理。但是我们失去了在变量被赋值之后立即需要的函数调用或处理的灵活性,我们可以通过__post_init__来实现,例如以下在初始化之后立即计算整数和小数部分

import math


@dataclass
class FloatNumber:
    val: float = 0.0

    def __post_init__(self):
        self.decimal, self.integer = math.modf(self.val)
>>> a = Number(2.2)
>>> a.val
>>> 2.2
>>> a.integer
>>> 2.0
>>> a.decimal
>>> 0.2

继承

Dataclasses 支持继承,就像普通的 Python 类一样

@dataclass
class Person:
    age: int = 0
    name: str

@dataclass
class Student(Person):
    grade: int
>>> s = Student(20, "John Doe", 12)
>>> s.age
>>> 20
>>> s.name
>>> "John Doe"
>>> s.grade
>>> 12

Student 的参数是在类中定义的字段的顺序

field

先看下field的原型

dataclasses.field(*, default=MISSING, default_factory=MISSING, repr=True, hash=None, init=True, compare=True, metadata=None)

通常我们无需直接使用,装饰器会根据我们给出的类型注解自动生成field,但有时候我们也需要定制这一过程,这时dataclasses.field就显得格外有用了

from dataclasses import dataclass, field

@dataclass
class Position:

    lon: float = field(default=0.0, metadata={"unit": "degrees"})
    lat: float = field(default=0.0, metadata={"unit": "degrees"})
>>>from dataclasses import fields
>>>fields(Position)[1].metadata["unit"]
>>>degrees

我们再来试下default_factory,如果在创建对象时没有赋值,则使用该方法初始化该字段

from dataclasses import dataclass, field


def get_grades():
    return [random.randint(60, 100) for _ in range(3)]


@dataclass
class Student:
    grades: List[int] = field(default_factory=get_grades)
>>>Student().grades
>>>[95, 89, 60]

当然我们也可以使用__post_init__来实现

版权声明:如无特殊说明,文章均为本站原创,转载请注明出处

本文链接:https://www.ltfred.com/article/python-dataclass/