概述
问题已解决。但是,此答案添加了一些实际示例,以帮助对数据类进行基本理解。
什么是 python 数据类,什么时候最好使用它们?
-
代码生成器:生成样板代码;您可以选择在常规类中实现特殊方法或让数据类自动实现它们。
-
数据容器:保存数据的结构(例如元组和字典),通常带有点属性访问,例如classes,
namedtuple and others。
“具有默认值[s]的可变命名元组”
后一句的意思如下:
-
可变:默认情况下,数据类属性可以重新分配。您可以选择使它们不可变(参见下面的示例)。
-
namedtuple:你有类似
namedtuple 或普通类的点属性访问。
-
default:您可以为属性分配默认值。
与普通类相比,您主要节省了键入样板代码。
特点
这是对数据类功能的概述(TL;DR?请参阅下一节中的汇总表)。
你会得到什么
以下是您默认从数据类中获得的功能。
属性+表示+比较
import dataclasses
@dataclasses.dataclass
#@dataclasses.dataclass() # alternative
class Color:
r : int = 0
g : int = 0
b : int = 0
这些默认值是通过自动将以下关键字设置为 True 来提供的:
@dataclasses.dataclass(init=True, repr=True, eq=True)
你可以打开什么
如果将适当的关键字设置为True,则可以使用其他功能。
顺序
@dataclasses.dataclass(order=True)
class Color:
r : int = 0
g : int = 0
b : int = 0
现在实现了排序方法(重载运算符:< > <= >=),类似于具有更强相等性测试的functools.total_ordering。
可散列、可变
@dataclasses.dataclass(unsafe_hash=True) # override base `__hash__`
class Color:
...
虽然对象可能是可变的(可能是不希望的),但实现了哈希。
可散列,不可变
@dataclasses.dataclass(frozen=True) # `eq=True` (default) to be immutable
class Color:
...
现在实现了哈希,并且不允许更改对象或分配给属性。
总体而言,如果unsafe_hash=True 或frozen=True,则该对象是可散列的。
有关更多详细信息,另请参阅原始 hashing logic table。
你没有得到什么
要获得以下特性,必须手动实现特殊方法:
拆包
@dataclasses.dataclass
class Color:
r : int = 0
g : int = 0
b : int = 0
def __iter__(self):
yield from dataclasses.astuple(self)
优化
@dataclasses.dataclass
class SlottedColor:
__slots__ = ["r", "b", "g"]
r : int
g : int
b : int
对象大小现在减小了:
>>> imp sys
>>> sys.getsizeof(Color)
1056
>>> sys.getsizeof(SlottedColor)
888
在某些情况下,__slots__ 还提高了创建实例和访问属性的速度。此外,插槽不允许默认分配;否则,将引发 ValueError。
在blog post 中查看更多关于插槽的信息。
汇总表
+----------------------+----------------------+----------------------------------------------------+-----------------------------------------+
| Feature | Keyword | Example | Implement in a Class |
+----------------------+----------------------+----------------------------------------------------+-----------------------------------------+
| Attributes | init | Color().r -> 0 | __init__ |
| Representation | repr | Color() -> Color(r=0, g=0, b=0) | __repr__ |
| Comparision* | eq | Color() == Color(0, 0, 0) -> True | __eq__ |
| | | | |
| Order | order | sorted([Color(0, 50, 0), Color()]) -> ... | __lt__, __le__, __gt__, __ge__ |
| Hashable | unsafe_hash/frozen | {Color(), {Color()}} -> {Color(r=0, g=0, b=0)} | __hash__ |
| Immutable | frozen + eq | Color().r = 10 -> TypeError | __setattr__, __delattr__ |
| | | | |
| Unpacking+ | - | r, g, b = Color() | __iter__ |
| Optimization+ | - | sys.getsizeof(SlottedColor) -> 888 | __slots__ |
+----------------------+----------------------+----------------------------------------------------+-----------------------------------------+
+这些方法不会自动生成,需要在数据类中手动实现。
*__ne__ 不需要,因此not implemented。
附加功能
初始化后
@dataclasses.dataclass
class RGBA:
r : int = 0
g : int = 0
b : int = 0
a : float = 1.0
def __post_init__(self):
self.a : int = int(self.a * 255)
RGBA(127, 0, 255, 0.5)
# RGBA(r=127, g=0, b=255, a=127)
继承
@dataclasses.dataclass
class RGBA(Color):
a : int = 0
转化次数
将数据类转换为元组或字典,recursively:
>>> dataclasses.astuple(Color(128, 0, 255))
(128, 0, 255)
>>> dataclasses.asdict(Color(128, 0, 255))
{'r': 128, 'g': 0, 'b': 255}
限制
参考文献