Python 什么是数据类?它们与普通类有何不同?

Python 什么是数据类?它们与普通类有何不同?,python,class,python-3.7,python-dataclasses,Python,Class,Python 3.7,Python Dataclasses,随着数据类被引入python标准库 它们使用了@dataclass装饰器,它们被认为是“带默认值的可变名称耦合”,但我不太清楚这到底意味着什么,以及它们与普通类的区别 python数据类到底是什么?什么时候最好使用它们?来自: 提供了一个类装饰器,用于检查类定义的 带有类型注释的变量,如PEP 526“语法”中所定义 变量注释”。在本文档中,此类变量称为 领域。使用这些字段,装饰器添加生成的方法 类的定义以支持实例初始化,repr, 比较方法,以及中所述的可选其他方法 规范部分。这样的类称为数据

随着数据类被引入python标准库

它们使用了
@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数据类到底是什么?什么时候最好使用它们

  • 代码生成器:生成样板代码;您可以选择在常规类中实现特殊方法,或者让dataclass自动实现它们
  • 数据容器:保存数据的结构(例如元组和dict),通常具有点式属性访问,例如
  • “可变名称与默认值的耦合”

    后一个短语的意思如下:

    • 可变:默认情况下,可以重新分配数据类属性。您可以选择使它们不可变(参见下面的示例)
    • 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