kin*_*ian 82 python class python-3.7 python-dataclasses
使用PEP 557,数据类被引入到python标准库中.
他们使用@dataclass
装饰器,他们应该是"默认的可变的命名元组",但我不确定我理解这实际意味着什么,以及它们与普通类的区别.
究竟什么是python数据类以及何时最好使用它们?
Mar*_*ers 100
数据类只是面向存储状态的常规类,而不仅仅包含大量逻辑.每次创建一个主要由属性组成的类时,您创建了一个数据类.
该dataclasses
模块的作用是使创建数据类更容易.它可以为您提供大量的锅炉盘.
当您的数据类必须是可清除时,这一点尤其重要; 这需要一种__hash__
方法和一种__eq__
方法.如果添加自定义__repr__
方法以便于调试,则可能会变得非常冗长:
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))
Run Code Online (Sandbox Code Playgroud)
有了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
Run Code Online (Sandbox Code Playgroud)
同一类的装饰也可以产生比较方法(__lt__
,__gt__
等)和处理不变性.
namedtuple
类也是数据类,但默认情况下是不可变的(以及序列).dataclasses
在这方面要灵活得多,并且可以很容易地构建,以便它们可以充当与namedtuple
班级相同的角色.
PEP的灵感来自该attrs
项目,该项目可以做得更多(包括插槽,验证器,转换器,元数据等).
如果你想看到一些例子,我最近使用dataclasses
了几个我的代码的问世解决方案,请参阅解决方案7天,8天,11天和20天.
如果你想dataclasses
在Python版本<3.7中使用模块,那么你可以安装backported模块(需要3.6)或使用attrs
上面提到的项目.
pyl*_*ang 31
这个问题已得到解决.但是,这个答案增加了一些实际的例子来帮助对数据类进行基本的理解.
究竟什么是python数据类以及何时最好使用它们?
namedtuple
等."具有默认[s]的可变命名元组"
以下是后一个短语的含义:
namedtuple
一个普通的类.与普通类相比,您主要是在键入样板代码.
以下是数据类功能的概述(请参阅摘要表中的示例).
以下是默认情况下从数据类中获得的功能.
属性+表示+比较
import dataclasses
@dataclasses.dataclass
#@dataclasses.dataclass() # alternative
class Color:
r : int = 0
g : int = 0
b : int = 0
Run Code Online (Sandbox Code Playgroud)
以下默认值自动设置为True
:
@dataclasses.dataclass(init=True, repr=True, eq=True)
Run Code Online (Sandbox Code Playgroud)
如果设置了适当的关键字,则可以使用其他功能True
.
订购
@dataclasses.dataclass(order=True)
class Color:
r : int = 0
g : int = 0
b : int = 0
Run Code Online (Sandbox Code Playgroud)
现在实现了排序方法(重载运算符< > <= >=
:),类似于functools.total_ordering
更强的相等性测试.
可洗,可变
@dataclasses.dataclass(unsafe_hash=True) # override base `__hash__`
class Color:
...
Run Code Online (Sandbox Code Playgroud)
尽管该对象可能是可变的(可能是不期望的),但实现了散列.
可洗,不变
@dataclasses.dataclass(frozen=True) # `eq=True` (default) to be immutable
class Color:
...
Run Code Online (Sandbox Code Playgroud)
现在实现了哈希,并且不允许更改对象或分配属性.
总的来说,如果是unsafe_hash=True
或者对象是可以清洗的frozen=True
.
另请参阅原始哈希逻辑表以及更多详细信息.
要获得以下功能,必须手动实现特殊方法:
Unpackable
@dataclasses.dataclass
class Color:
r : int = 0
g : int = 0
b : int = 0
def __iter__(self):
yield from dataclasses.astuple(self)
Run Code Online (Sandbox Code Playgroud)
优化
@dataclasses.dataclass
class SlottedColor:
__slots__ = ["r", "b", "g"]
r : int
g : int
b : int
Run Code Online (Sandbox Code Playgroud)
对象大小现在减少了:
>>> imp sys
>>> sys.getsizeof(Color)
1056
>>> sys.getsizeof(SlottedColor)
888
Run Code Online (Sandbox Code Playgroud)
在某些情况下,__slots__
还可以提高创建实例和访问属性的速度.此外,插槽不允许默认分配; 否则,a ValueError
被提出.
查看更多关于插槽在这个博客帖子.
+----------------------+----------------------+----------------------------------------------------+-----------------------------------------+
| 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__ |
| | | | |
| Unpackable+ | - | r, g, b = Color() | __iter__ |
| Optimization+ | - | sys.getsizeof(SlottedColor) -> 888 | __slots__ |
+----------------------+----------------------+----------------------------------------------------+-----------------------------------------+
Run Code Online (Sandbox Code Playgroud)
+这些方法不是自动生成的,需要在数据类中手动实现.
* __ne__
在没有实现.
后初始化
@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)
Run Code Online (Sandbox Code Playgroud)
遗产
@dataclasses.dataclass
class RGBA(Color):
a : int = 0
Run Code Online (Sandbox Code Playgroud)
转换
以递归方式将数据类转换为元组或字典:
>>> dataclasses.astuple(Color(128, 0, 255))
(128, 0, 255)
>>> dataclasses.asdict(Color(128, 0, 255))
{r: 128, g: 0, b: 255}
Run Code Online (Sandbox Code Playgroud)
限制
Mes*_*ssa 15
顺便说一句.Raymond Hettinger(Python核心开发人员)在PyCon 2018上进行了精彩的演讲:
https://www.youtube.com/watch?v=T-TwcmT6Rcw&t=1390
幻灯片在这里:https://twitter.com/raymondh/status/995693882812915712
考虑这个简单的类Foo
from dataclasses import dataclass
@dataclass
class Foo:
def bar():
pass
Run Code Online (Sandbox Code Playgroud)
这是dir()
内置的比较。左侧是Foo
没有 @dataclass 装饰器的情况,右侧是带有 @dataclass 装饰器的情况。
这是使用模块进行比较后的另一个差异inspect
。
归档时间: |
|
查看次数: |
25721 次 |
最近记录: |