使用 Python 数据类的 10 个令人信服的理由
Python 在3.7 版(PEP 557)中引入了数据类。顾名思义,数据类包含数据,使我们能够在类中解锁更多功能。
概述
传统上,我们使用特殊方法来初始化类属性并在这些属性之间执行操作。但是,当开发人员花费大量时间编写具有许多属性的特殊方法时,这让他们很头疼。
数据类通过向普通类添加更多功能同时提供更少代码来减少这些问题。
好的,让我们了解为什么 Dataclasses 比普通类更好
1.用更少的代码定义你的类
当我们用__init__方法定义类时,它看起来像这样。
class Student:
def __init__(self, name, clss, stu_id):
self.name = name
self.clss = clss
self.stu_id = stu_id
但是当你用数据类定义一个类时,你可以在类声明上方使用@dataclass 装饰器。
from dataclasses import dataclass
@dataclass
class Student:
name: str
clss: str
stu_id: int
上述代码中值得注意的地方:
- 不在需要初始化函数来初始化类属性。
- 我们用类型提示定义每个属性,例如,name: str表示 name 属性应该是字符串类型。
2.设置默认值
你可以为需要的字段提供默认值。
from dataclasses import dataclass
@dataclass
class Student:
name: str = 'Sam'
clss: str = '10th'
stu_id: int = '10101'
永远不要忘记,没有默认值的字段总是排在第一位。如果你更改顺序,则会引发错误。
3. 表示可读对象
python 数据类支持__repr__因此在打印对象时它提供更好的可读性。
from dataclasses import dataclass
@dataclass
class Student:
name: str = 'Sam'
clss: str = '10th'
stu_id: int = '10101'
Stu_1 = Student()
print(Stu_1)
# Output: Student(name='Sam', clss='10th', stu_id='10101')
4.创建不可变对象
你可以创建只读对象,你所要做的就是在@dataclass装饰器中将frozen参数设置为True 。
这将防止任何人修改属性。
from dataclasses import dataclass
@dataclass(frozen=True)
class Student:
name: str = 'Sam'
clss: str = '10th'
stu_id: int = '10101'
stu1 = Student()
print(stu1)
stu1.name = "Jack"
5. 轻松转换元组或字典
借助astuple()和asdict()函数,我们可以轻松地将数据类实例转换为元组和字典。
from dataclasses import dataclass, astuple, asdict
@dataclass
class Student:
name: str = 'Sam'
clss: str = '10th'
stu_id: int = '10101'
Stu_1 = Student()
# tuple conversion
print(astuple(Stu_1))
# Output:('Sam', '10th', '10101')
# Dictionary conversion
print(asdict(Stu_1))
# Output: {'name': 'Sam', 'clss': '10th', 'stu_id': '10101'}
6. 轻松比较对象
如果你检查在标准类声明中具有相同值的两个对象之间的相等性,它会给你 False。
class Student:
def __init__(self, name, clss, stu_id):
self.name = name
self.clss = clss
self.stu_id = stu_id
Stu_1 = Student('Sam', '1oth', '10101')
Stu_2 = Student('Sam', '1oth', '10101')
print(Stu_1 == Stu_2)
# Output: False
这两个对象具有相同的值,但我们的答案是 False,这是因为我们没有实现__eq__方法。
from dataclasses import dataclass
@dataclass
class Student:
name: str = 'Sam'
clss: str = '10th'
stu_id: int = '10101'
Stu_1 = Student()
Stu_2 = Student()
print(Stu_1 == Stu_2)
# Output: True
当我们用@dataclass 声明类时,这两个对象给出 True,因为它支持 __eq__ 方法。
7. 自定义属性行为
如果你不想在实例化类时初始化属性,可以使用字段函数。
通过使用 field 函数并将init和repr参数设置为False,你可以在不初始化 Percentage 的情况下创建 Student 类。
from dataclasses import dataclass, field
@dataclass
class Student:
name: str = 'Sam'
clss: str = '10th'
stu_id: int = '10101'
marks: int = 479
percentage: str = field(init=False, repr=False)
百分比属性尚不存在。如果你尝试访问它,这将抛出AttributeError。
8. __post_init__
数据类有一个名为 __post_init__ 的特殊方法。
此方法将帮助我们初始化一个依赖于另一个属性值的属性。顾名思义,Python 在 __init__ 方法之后调用 __post_init__ 方法。
回到前面的例子,我们可以看到这个方法是如何初始化百分比属性的。
from dataclasses import dataclass, field
@dataclass
class Student:
name: str = 'Sam'
clss: str = '10th'
stu_id: int = '10101'
marks: int = 479
percentage: str = field(init=False, repr=True)
def __post_init__(self):
self.percentage = str((self.marks/500)*100)+'%'
Stu_1 = Student()
print(Stu_1)
# Output: Student(name='Sam', clss='10th', stu_id='10101', marks=479, percentage='95.8%')
print(Stu_1.percentage)
# Output: 95.8%
请注意,字段函数内的repr参数已设置为 True 以使其在打印对象时可见。
9. 比较对象
默认情况下,数据类实现 __eq__ 方法。
要允许不同类型的比较,如__lt__、__lte__、__gt__、__ gte__,你可以将@dataclass装饰器的顺序参数设置为 True。
通过这样做,数据类将按每个字段比较对象,直到找到不相等的值。
from dataclasses import dataclass, field
@dataclass(order=True)
class Student:
name: str = 'Sam'
clss: str = '10th'
stu_id: int = '10101'
marks: int = 479
percentage: str = field(init=False, repr=False)
def __post_init__(self):
self.percentage = str((self.marks/500)*100)+'%'
Stu_1 = Student(marks=479)
Stu_2 = Student(marks=470)
print(Stu_1 < Stu_2)
# Output: False
10. 支持可变默认值
在某些情况下,你可能需要创建一个具有默认可变属性的类。
通过使用default_factory你可以创建可变的默认属性。让我们在列表中给 Student 类打分。
from dataclasses import dataclass, field
from typing import List
@dataclass(order=True)
class Student:
name: str = 'Sam'
clss: str = '10th'
stu_id: int = '10101'
marks: List = field(default_factory=lambda: [94, 88, 99, 100, 98])
请注意,default_factory仅采用零参数可调用,这就是我们使用lambda函数的原因。
数据类使我们能够高效地使用类。
具体来说,该模块有助于:
- 少写代码。
- 以可读格式表示对象。
- 创建不可变对象。
- 提供 astuple() 和 asdict() 函数将数据类的对象转换为元组和字典。
- 提供自定义属性行为。
- 使用 __post_init__ 方法初始化依赖于其他属性的属性。
- 实施自定义排序和比较。
- 创建默认的可变属性。
如果你发现我的任何文章对你有帮助或者有用,麻烦点赞或者转发。 谢谢!