数据类与typing.NamedTuple主要用例

问题描述 投票:11回答:2

长话短说

PEP-557将数据类引入Python标准库,基本上可以填充与collections.namedtupletyping.NamedTuple相同的角色。现在我想知道如何分离使用namedtuple仍然是更好的解决方案的用例。

数据类优于NamedTuple

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

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

数据类优势在同一个PEP中简要解释:Why not just use namedtuple

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

但是对于namedtuples这个相反的问题呢:为什么不使用dataclass呢?我想从性能的角度来看,名字元组可能更好,但尚未确认。

让我们考虑以下情况:

我们将页面维度存储在一个小容器中,该容器具有静态定义的字段,类型提示和命名访问。不需要进一步散列,比较等。

NamedTuple方法:

from typing import NamedTuple

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

DataClass方法:

from dataclasses import dataclass

@dataclass
class PageDimensions:
    width: int
    height: int

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

附:这个问题不是that one的重复,因为在这里我问的是关于namedtuple更好的情况,而不是差异(我在询问之前检查了文档和来源)

python namedtuple pep python-3.7 python-dataclasses
2个回答
6
投票

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

这是PyCon 2018 Raymond Hettinger - Dataclasses: The code generator to end all code generators上Dataclasses的一个很好的解释

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

但Dataclass基于dup为基于元组的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。


3
投票

在编程中,任何可以不可变的东西都应该是不可变的。我们获得了两件事:

  1. 更容易阅读程序 - 我们不需要担心值的变化,一旦它被实例化,它将永远不会改变(namedtuple)
  2. 减少奇怪错误的机会

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

我在评论中写了它,但我会在这里提到它:你肯定是有重叠的,尤其是数据类中的frozen=True - 但仍然有一些功能,例如解包属于namedtuples,它总是不可变的 - 我怀疑他们会删除这样的命名元组

© www.soinside.com 2019 - 2024. All rights reserved.