Python 什么是数据类?它们与普通类有何不同?
随着数据类被引入python标准库 它们使用了Python 什么是数据类?它们与普通类有何不同?,python,class,python-3.7,python-dataclasses,Python,Class,Python 3.7,Python Dataclasses,随着数据类被引入python标准库 它们使用了@dataclass装饰器,它们被认为是“带默认值的可变名称耦合”,但我不太清楚这到底意味着什么,以及它们与普通类的区别 python数据类到底是什么?什么时候最好使用它们?来自: 提供了一个类装饰器,用于检查类定义的 带有类型注释的变量,如PEP 526“语法”中所定义 变量注释”。在本文档中,此类变量称为 领域。使用这些字段,装饰器添加生成的方法 类的定义以支持实例初始化,repr, 比较方法,以及中所述的可选其他方法 规范部分。这样的类称为数据
@dataclass
装饰器,它们被认为是“带默认值的可变名称耦合”,但我不太清楚这到底意味着什么,以及它们与普通类的区别
python数据类到底是什么?什么时候最好使用它们?来自:
提供了一个类装饰器,用于检查类定义的
带有类型注释的变量,如PEP 526“语法”中所定义
变量注释”。在本文档中,此类变量称为
领域。使用这些字段,装饰器添加生成的方法
类的定义以支持实例初始化,repr,
比较方法,以及中所述的可选其他方法
规范部分。这样的类称为数据类,但是
“这门课真的没有什么特别之处,”装饰师补充道
将生成的方法返回给该类,并返回与该类相同的类
给定的
@dataclass
生成器将方法添加到类中,否则您将自己定义为\uuuu repr\uuu
,\uuu init\uuuu
,\uu lt\uuuuu
,\uu gt\uuuu数据类只是用于存储状态的常规类,而不是包含大量逻辑。每次创建一个主要由属性组成的类时,都会创建一个数据类
dataclasses
模块所做的是使创建数据类变得更容易。它为你处理了很多样板文件
当数据类必须是可散列的时,这尤其有用;因为这需要一个\uuuuuuuuuuuuuuuuuuuuuuu散列
方法以及一个\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
方法。如果为了便于调试而添加自定义的\u_repr\u_
方法,则可能会变得非常冗长:
class InventoryItem:
'''Class for keeping track of an item in inventory.'''
name: str
unit_price: float
quantity_on_hand: int = 0
def __init__(
self,
name: str,
unit_price: float,
quantity_on_hand: int = 0
) -> None:
self.name = name
self.unit_price = unit_price
self.quantity_on_hand = quantity_on_hand
def total_cost(self) -> float:
return self.unit_price * self.quantity_on_hand
def __repr__(self) -> str:
return (
'InventoryItem('
f'name={self.name!r}, unit_price={self.unit_price!r}, '
f'quantity_on_hand={self.quantity_on_hand!r})'
def __hash__(self) -> int:
return hash((self.name, self.unit_price, self.quantity_on_hand))
def __eq__(self, other) -> bool:
if not isinstance(other, InventoryItem):
return NotImplemented
return (
(self.name, self.unit_price, self.quantity_on_hand) ==
(other.name, other.unit_price, other.quantity_on_hand))
使用dataclasses
可以将其简化为:
from dataclasses import dataclass
@dataclass(unsafe_hash=True)
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
同一个类修饰符还可以生成比较方法(\uuult\uuuuu
,\uu gt\uuuu
等)并处理不变性
namedtuple
类也是数据类,但在默认情况下是不可变的(也是序列)<代码>数据类
在这方面更加灵活,并且可以很容易地进行结构化,使它们能够
PEP的灵感来自,它可以做更多的事情(包括插槽、验证器、转换器、元数据等)
如果您想查看一些示例,我最近使用了dataclasses
作为我的几个解决方案,请参阅和的解决方案
如果要在Python版本<3.7中使用dataclasses
模块,则可以安装(需要3.6)或使用上述attrs
项目。概述
这个问题已经解决了。然而,这个答案添加了一些实际的例子来帮助基本理解数据类
python数据类到底是什么?什么时候最好使用它们
- 可变:默认情况下,可以重新分配数据类属性。您可以选择使它们不可变(参见下面的示例)
- namedtuple:您具有点式的属性访问,如
或常规类namedtuple
- 默认值:可以为属性指定默认值
特征 这是数据类功能的概述(TL;DR?请参阅下一节中的汇总表) 你得到了什么 以下是默认情况下从DataClass获得的功能 属性+表示+比较 通过自动将以下关键字设置为
True
,可以提供这些默认值:
@dataclasses.dataclass(init=True, repr=True, eq=True)
你能打开什么
如果适当的关键字设置为True
,则可以使用其他功能
命令
现在实现了排序方法(重载运算符:=
),类似于更强的相等性测试
可散列的,可变的
尽管对象可能是可变的(可能是不需要的),但还是实现了哈希
可散列的,不可变的
现在实现了哈希,不允许更改对象或指定属性
总的来说,如果unsafe\u hash=True
或freezed=True
,则对象是可散列的
更多细节请参见原件
你没有得到什么
要获得以下功能,必须手动执行特殊方法:
拆包
优化
对象大小现在已减小:
>>> imp sys
>>> sys.getsizeof(Color)
1056
>>> sys.getsizeof(SlottedColor)
888
在某些情况下,\uuuuuu\uuuuuu
还可以提高创建实例和访问属性的速度。此外,插槽不允许默认分配;否则,将引发ValueError
请参阅本节中有关插槽的更多信息
汇总表 +这些方法不是自动生成的,需要在数据类中手动实现 *
\uuu ne\uuu
是不需要的,因此
附加功能 初始化后 继承权 转换 将数据类转换为元组或dict,: 局限性
- 缺乏处理机制
- 与客户合作可能会很复杂
工具书类
- R.Hettinger关于数据类:结束所有代码生成器的代码生成器
- T.Hunner关于更简单的类:没有所有缺点的Python类
- Python的哈希细节
- 真正的Python关于数据类的终极指南
@dataclasses.dataclass(order=True) class Color: r : int = 0 g : int = 0 b : int = 0
@dataclasses.dataclass(unsafe_hash=True) # override base `__hash__` class Color: ...
@dataclasses.dataclass(frozen=True) # `eq=True` (default) to be immutable class Color: ...
@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
+----------------------+----------------------+----------------------------------------------------+-----------------------------------------+ | 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__ | +----------------------+----------------------+----------------------------------------------------+-----------------------------------------+
@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
>>> dataclasses.astuple(Color(128, 0, 255)) (128, 0, 255) >>> dataclasses.asdict(Color(128, 0, 255)) {'r': 128, 'g': 0, 'b': 255}
from dataclasses import dataclass @dataclass class Foo: def bar(): pass