数据类与输入。NamedTuple主要用例

时间:2018-08-03 11:32:05

标签: python namedtuple pep python-3.7 python-dataclasses

长话短说

PEP-557在Python标准库中引入了数据类,该数据类基本上可以起到与collections.namedtupletyping.NamedTuple相同的作用。现在,我想知道如何将用例命名为仍然更好的解决方案分开。

数据类优于NamedTuple

当然,如果需要,所有功劳都归功于dataclass

  • 可变对象
  • 继承支持
  • property装饰器,可管理的属性
  • 立即生成的方法定义或可自定义的方法定义

在同一Why not just use namedtuple的PEP中简要说明了数据类的优点。

问:在哪些情况下,命名元组仍然是更好的选择?

但是对namedtuples来说却是一个相反的问题:为什么不只使用dataclass? 从性能的角度来看,我认为namedtuple可能更好,但尚未对此进行确认。

示例

让我们考虑以下情况:

我们将页面尺寸存储在一个带有静态定义字段,键入提示和命名访问权限的小容器中。无需进一步的哈希,比较等。

NamedTuple方法:

from typing import NamedTuple

PageDimensions = NamedTuple("PageDimensions", [('width', int), ('height', int)])

DataClass方法:

from dataclasses import dataclass

@dataclass
class PageDimensions:
    width: int
    height: int

哪种解决方案更可取,为什么?

P.S。这个问题绝不是that one的重复,因为我在这里问的是 namedtuple更好的情况,而不是区别 (在询问之前,我已经检查了文档和来源)

3 个答案:

答案 0 :(得分:6)

这取决于您的需求。他们每个人都有自己的利益。

这是PyCon 2018 Raymond Hettinger - Dataclasses: The code generator to end all code generators

上数据类的很好解释

在Dataclass中,所有实现都是用Python编写的,就像Namedtuple一样,所有这些行为都是免费的,因为Namedtuple继承自tuple。元组结构用C编写,这就是为什么Namedtuple中的标准方法更快(哈希,比较等)的原因。

但是,数据类基于dict,即基于元组的Namedtuple。据此,使用这些结构具有优点和缺点。例如,NamedTuple中的空间使用量较小,而Dataclass中的时间访问速度更快。

请看我的实验:

In [33]: a = PageDimensionsDC(width=10, height=10)

In [34]: sys.getsizeof(a) + sys.getsizeof(vars(a))
Out[34]: 168

In [35]: %timeit a.width
43.2 ns ± 1.05 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

In [36]: a = PageDimensionsNT(width=10, height=10)

In [37]: sys.getsizeof(a)
Out[37]: 64

In [38]: %timeit a.width
63.6 ns ± 1.33 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

但是随着NamedTuple属性数量的增加,访问时间仍然保持不变,因为它会为每个属性创建一个带有属性名称的属性。例如,对于我们来说,新类的名称空间部分将如下所示:

from operator import itemgetter

class_namespace = {
...
    'width': property(itemgetter(0, doc="Alias for field number 0")),
    'height': property(itemgetter(0, doc="Alias for field number 1"))**
}
  

在哪些情况下,namedtuple仍然是更好的选择?

当您的数据结构需要/可以不可变,可哈希,可迭代,不可打包,可比较时,可以使用NamedTuple。例如,如果您需要更复杂的东西,则有可能需要继承数据结构,请使用Dataclass。

答案 1 :(得分:2)

通常,在编程中,任何不可变的东西都应该不可变的。我们得到两件事:

  1. 易于阅读的程序-我们无需担心值更改,一旦实例化,它就永远不会更改(命名元组)
  2. 出现奇怪错误的机会很少

这就是为什么如果数据是不可变的,则应该使用命名元组而不是数据类

我在评论中写了它,但我会在这里提及: 您肯定是对的,尤其是在数据类中与frozen=True有重叠的地方-但是仍然存在诸如拆包namedtuple的功能,并且它始终是不可变的-我怀疑它们会这样删除namedtuples

答案 2 :(得分:1)

我也有同样的问题,因此进行了一些测试并在此处进行了记录:

https://shayallenhill.com/python-struct-options/

要点是,namedtuple更适合拆包,爆炸和调整大小。数据类更快,更灵活。

差别不大,我不会重构稳定的代码以从一个代码移到另一个代码。