数据 类 与 typing.NamedTuple 主要用例
Data Classes vs typing.NamedTuple primary use cases
长话短说
PEP-557 将数据类 引入Python 标准库,基本上可以起到与collections.namedtuple
和typing.NamedTuple
相同的作用。现在我想知道如何分离 namedtuple 仍然是更好解决方案的用例。
Data 类 优于 NamedTuple
当然,如果我们需要,所有功劳都归于dataclass
:
- 可变对象
- 继承支持
property
装饰器,可管理的属性
- 开箱即用的生成方法定义或可自定义的方法定义
数据 类 优点在同一 PEP 中进行了简要说明:Why not just use namedtuple。
问:在哪些情况下 namedtuple 仍然是更好的选择?
但是关于命名元组的相反问题如何:为什么不只使用数据类?
我想从性能的角度来看,namedtuple 可能更好,但尚未找到证实。
例子
让我们考虑以下情况:
我们将把页面维度存储在一个带有静态定义字段、类型提示和命名访问的小容器中。不需要进一步的散列、比较等。
NamedTuple 方法:
from typing import NamedTuple
PageDimensions = NamedTuple("PageDimensions", [('width', int), ('height', int)])
数据类方法:
from dataclasses import dataclass
@dataclass
class PageDimensions:
width: int
height: int
哪种解决方案更可取,为什么?
P.S。这个问题在任何方面都不是 的重复,因为在这里我问的是 namedtuple 更好的情况 ,而不是 差异(我在询问之前检查了文档和来源)
在一般编程中,任何可以不可变的东西都应该是不可变的。我们收获了两件事:
- 更易于阅读程序 - 我们无需担心值会发生变化,一旦实例化,它就永远不会改变 (namedtuple)
- 出现奇怪错误的几率降低
这就是为什么如果数据不可变,您应该使用命名元组而不是数据类
我在评论里写了,但我会在这里提到它:
你绝对是对的,有重叠,尤其是数据类中的 frozen=True
- 但仍然有一些特性,例如属于 namedtuples 的解包,并且它总是不可变的 - 我怀疑他们会删除 namedtuples
这取决于您的需求。他们每个人都有自己的好处。
这是 PyCon 2018 上 Dataclasses 的一个很好的解释 Raymond Hettinger - Dataclasses: The code generator to end all code generators
在Dataclass
中,所有实现都写在Python中,而在NamedTuple
中,所有这些行为都是免费的,因为NamedTuple
继承自 tuple
。因为 tuple
结构是用 C 编写的,标准方法在 NamedTuple
中更快(散列、比较等)。
还要注意 Dataclass
基于 dict
而 NamedTuple
基于 tuple
。因此,使用这些结构既有优点也有缺点。例如,space 使用 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
属性数量的增加,访问时间仍然很短,因为它为每个属性创建一个 属性 和属性名称。例如,对于我们的案例,新 class 的名称 space 部分将如下所示:
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"))**
}
In which cases namedtuple is still a better choice?
当你的数据结构需要 to/can 是 不可变的、可散列的、可迭代的、不可压缩的、可比较的时,你可以使用 NamedTuple
。如果您需要更复杂的东西,例如,为您的数据结构继承的可能性,那么使用Dataclass
。
我有同样的问题,所以 运行 进行了一些测试并记录在此处:https://shayallenhill.com/python-struct-options/
总结:
- NamedTuple 更适合解包、分解和大小。
- DataClass 更快更灵活。
- 差异并不大,我不会重构稳定代码以从一个代码转移到另一个代码。
- 当您希望能够传递元组时,NamedTuple 也非常适合软键入。
为此,定义一个继承自它的类型...
class CircleArg(NamedTuple):
x: float
y: float
radius: float
...然后将其解压到您的函数中。不要使用 .attributes
,你会得到一个很好的“类型提示”,而不会为调用者提供任何 PITA。
*focus, radius = circle_arg_instance # or tuple
我的一个用例是不支持 dataclasses
的框架。特别是 TensorFlow。在那里,tf.function
可以与 typing.NamedTuple
一起使用,但不能与 dataclass
.
一起使用
class MyFancyData(typing.NamedTuple):
some_tensor: tf.Tensor
some_other_stuf: ...
@tf.function
def train_step(self, my_fancy_data: MyFancyData):
...
NamedTuple
的另一个重要限制是它不能通用:
import typing as t
T=t.TypeVar('T')
class C(t.Generic[T], t.NamedTuple): ...
TypeError: Multiple inheritance with NamedTuple is not supported
长话短说
PEP-557 将数据类 引入Python 标准库,基本上可以起到与collections.namedtuple
和typing.NamedTuple
相同的作用。现在我想知道如何分离 namedtuple 仍然是更好解决方案的用例。
Data 类 优于 NamedTuple
当然,如果我们需要,所有功劳都归于dataclass
:
- 可变对象
- 继承支持
property
装饰器,可管理的属性- 开箱即用的生成方法定义或可自定义的方法定义
数据 类 优点在同一 PEP 中进行了简要说明:Why not just use namedtuple。
问:在哪些情况下 namedtuple 仍然是更好的选择?
但是关于命名元组的相反问题如何:为什么不只使用数据类? 我想从性能的角度来看,namedtuple 可能更好,但尚未找到证实。
例子
让我们考虑以下情况:
我们将把页面维度存储在一个带有静态定义字段、类型提示和命名访问的小容器中。不需要进一步的散列、比较等。
NamedTuple 方法:
from typing import NamedTuple
PageDimensions = NamedTuple("PageDimensions", [('width', int), ('height', int)])
数据类方法:
from dataclasses import dataclass
@dataclass
class PageDimensions:
width: int
height: int
哪种解决方案更可取,为什么?
P.S。这个问题在任何方面都不是
在一般编程中,任何可以不可变的东西都应该是不可变的。我们收获了两件事:
- 更易于阅读程序 - 我们无需担心值会发生变化,一旦实例化,它就永远不会改变 (namedtuple)
- 出现奇怪错误的几率降低
这就是为什么如果数据不可变,您应该使用命名元组而不是数据类
我在评论里写了,但我会在这里提到它:
你绝对是对的,有重叠,尤其是数据类中的 frozen=True
- 但仍然有一些特性,例如属于 namedtuples 的解包,并且它总是不可变的 - 我怀疑他们会删除 namedtuples
这取决于您的需求。他们每个人都有自己的好处。
这是 PyCon 2018 上 Dataclasses 的一个很好的解释 Raymond Hettinger - Dataclasses: The code generator to end all code generators
在Dataclass
中,所有实现都写在Python中,而在NamedTuple
中,所有这些行为都是免费的,因为NamedTuple
继承自 tuple
。因为 tuple
结构是用 C 编写的,标准方法在 NamedTuple
中更快(散列、比较等)。
还要注意 Dataclass
基于 dict
而 NamedTuple
基于 tuple
。因此,使用这些结构既有优点也有缺点。例如,space 使用 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
属性数量的增加,访问时间仍然很短,因为它为每个属性创建一个 属性 和属性名称。例如,对于我们的案例,新 class 的名称 space 部分将如下所示:
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"))**
}
In which cases namedtuple is still a better choice?
当你的数据结构需要 to/can 是 不可变的、可散列的、可迭代的、不可压缩的、可比较的时,你可以使用 NamedTuple
。如果您需要更复杂的东西,例如,为您的数据结构继承的可能性,那么使用Dataclass
。
我有同样的问题,所以 运行 进行了一些测试并记录在此处:https://shayallenhill.com/python-struct-options/
总结:
- NamedTuple 更适合解包、分解和大小。
- DataClass 更快更灵活。
- 差异并不大,我不会重构稳定代码以从一个代码转移到另一个代码。
- 当您希望能够传递元组时,NamedTuple 也非常适合软键入。
为此,定义一个继承自它的类型...
class CircleArg(NamedTuple):
x: float
y: float
radius: float
...然后将其解压到您的函数中。不要使用 .attributes
,你会得到一个很好的“类型提示”,而不会为调用者提供任何 PITA。
*focus, radius = circle_arg_instance # or tuple
我的一个用例是不支持 dataclasses
的框架。特别是 TensorFlow。在那里,tf.function
可以与 typing.NamedTuple
一起使用,但不能与 dataclass
.
class MyFancyData(typing.NamedTuple):
some_tensor: tf.Tensor
some_other_stuf: ...
@tf.function
def train_step(self, my_fancy_data: MyFancyData):
...
NamedTuple
的另一个重要限制是它不能通用:
import typing as t
T=t.TypeVar('T')
class C(t.Generic[T], t.NamedTuple): ...
TypeError: Multiple inheritance with NamedTuple is not supported