Python dataclass 装饰器
最后修改于 2024 年 1 月 29 日
Python dataclass 教程展示了如何在自定义类中使用 Python 的 dataclass 装饰器。dataclass 装饰器有助于减少一些样板代码。
Python dataclass 装饰器
dataclass 装饰器用于自动为类生成特殊方法,包括 __str__ 和 __repr__。它有助于减少一些样板代码。dataclass 装饰器位于 dataclasses 模块中。
dataclass 装饰器会检查类以查找字段。字段定义为具有类型注解的类变量。
@dataclass class Test: ... @dataclass() class Test: ... @dataclass(init=True, repr=True, eq=True, order=False, unsafe_hash=False, frozen=False) class Test: ...
这三个声明是等效的。如果在装饰器中未设置参数,则会使用默认参数。如果 init 参数设置为 True,则会生成 __init__ 方法。如果类已定义 __init__,则忽略该参数。如果 repr 参数设置为 True,则会生成 __repr__ 方法。如果类已定义 __repr__,则忽略该参数。如果 eq 参数设置为 True,则会生成 __eq__ 方法。如果类已定义 __eq__,则忽略该参数。
如果 order 参数设置为 True,则会生成 __lt__、__le__、__gt__ 和 __ge__ 方法。如果类已定义任何这些方法,则会引发 ValueError。如果 unsafe_hash 定义为 False,则会根据 eq 和 frozen 的设置生成 __hash__ 方法。如果 frozen 参数设置为 True,则对字段的赋值将引发异常。
Python 普通自定义类
在普通的自定义 Python 类中,我们会手动提供构造函数和其他方法,如 __repr__。
#!/usr/bin/python
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __repr__(self):
return f'Person{{name: {self.name}, age: {self.age}}}'
p = Person('John Doe', 34)
print(p)
该示例显示了一个 Person 类,它有一个构造函数和 __repr__ 方法,该方法提供了对象的完整表示。
$ ./regular_class.py
Person{name: John Doe, age: 34}
Python dataclass 示例
以下示例展示了 dataclass 装饰器的简单用法。
#!/usr/bin/python
from dataclasses import dataclass
@dataclass
class Person:
name: str
age: int
p = Person('John Doe', 34)
print(p)
我们有一个包含两个字段的类:name 和 str。
from dataclasses import dataclass
dataclass 装饰器位于 dataclasses 模块中。
@dataclass
class Person:
name: str
age: int
我们将 dataclass 装饰器应用于 Person 类。
p = Person('John Doe', 34)
print(p)
创建了一个新的 person 对象。它的 __init__ 方法被调用,该方法由 dataclass 装饰器自动生成。
$ ./simple_dataclass.py Person(name='John Doe', age=34)
Python dataclass 默认值
可以为字段提供默认值。
#!/usr/bin/python
from dataclasses import dataclass
@dataclass
class Person:
name: str = 'unknown'
age: int = 0
p = Person('John Doe', 34)
print(p)
p2 = Person()
print(p2)
在该示例中,Person 类有两个字段;这些字段具有一些默认值。
@dataclass
class Person:
name: str = 'unknown'
age: int = 0
使用赋值运算符 (=),我们为字段提供默认值。
p2 = Person() print(p2)
当我们在构造函数中不提供值时,字段将具有默认值。
$ ./default_values.py Person(name='John Doe', age=34) Person(name='unknown', age=0)
dataclass frozen 参数
如果 frozen 参数设置为 True,则无法为字段赋值。
#!/usr/bin/python
from dataclasses import dataclass
@dataclass(frozen=True)
class Person:
name: str
age: int
p = Person('John Doe', 34)
p.occupation = 'gardener'
print(p)
print(p.occupation)
在该示例中,frozen 参数设置为 True。程序将因以下错误消息而失败:dataclasses.FrozenInstanceError: cannot assign to field 'occupation'。
dataclass asdict 函数
asdict 函数将 dataclass 实例转换为其字段的字典。
#!/usr/bin/python
from dataclasses import dataclass, asdict
@dataclass
class Person:
name: str
occupation: str
age: int
p = Person('John Doe', 'gardener', 34)
print(p)
print(asdict(p))
在该示例中,我们在 asdict 函数的帮助下打印 Person 类的字段。
$ ./as_dict_fun.py
Person(name='John Doe', occupation='gardener', age=34)
{'name': 'John Doe', 'occupation': 'gardener', 'age': 34}
第一行是 __repr__ 方法的输出。第二行是字段的字典。
dataclass field 函数
使用 field 函数,我们可以提供一些额外的每个字段信息。
#!/usr/bin/python
from dataclasses import dataclass, field
@dataclass
class Person:
name: str
age: int
occupation: str = field(init=False, repr=False)
p = Person('John Doe', 34)
print(p)
p.occupation = "Gardener"
print(f'{p.name} is a {p.occupation}')
在该示例中,我们有一个额外的 occupation 字段。
occupation: str = field(init=False, repr=False)
occupation 字段未包含在 __init__ 和 __repr__ 方法中。
$ ./fields.py Person(name='John Doe', age=34) John Doe is a Gardener
Python dataclass 和模式匹配
下一个示例使用数据类和模式匹配语法。
#!/usr/bin/python
from dataclasses import dataclass
@dataclass
class Point:
x: int
y: int
def check(p):
match p:
case Point(x=0, y=0):
print("Origin")
case Point(x, y) if y == 0:
print(f"on x axis")
case Point(x, y) if x == 0:
print(f"on y axis")
case Point(x, y) if x > 0 and y > 0:
print("Q I")
case Point(x, y) if x < 0 and y > 0:
print("Q II")
case Point(x, y) if x < 0 and y < 0:
print("Q III")
case Point(x, y) if x > 0 and y < 0:
print("Q IV")
case _:
print("Not a point")
points = [Point(3, 0), Point(0, 0), Point(-4, -5), Point(-4, 0), Point(0, 5),
Point(4, 8), Point(-5, 3), Point(6, -4)]
for p in points:
check(p)
我们有一个 Point 对象列表。使用 match/case 关键字,我们将每个点分配给原点、x 轴和 y 轴,或者四个象限之一。
case Point(x=0, y=0):
print("Origin")
在此 case 语句中,我们匹配一个 x=0 且 y=0 坐标的点。
case Point(x, y) if x > 0 and y > 0:
print("Q I")
使用 guard,我们检查点是否位于第一象限。
$ ./points.py on x axis Origin Q III on x axis on y axis Q I Q II Q IV
来源
在本文中,我们学习了 Python dataclass 装饰器。
作者
列出所有 Python 教程。