Python 数据类与typing.NamedTuple主要用例 长话短说
将数据类引入Python标准库,基本上可以充当与Python 数据类与typing.NamedTuple主要用例 长话短说,python,namedtuple,pep,python-3.7,python-dataclasses,Python,Namedtuple,Pep,Python 3.7,Python Dataclasses,将数据类引入Python标准库,基本上可以充当与collections.namedtuple和typing.namedtuple相同的角色。现在我想知道如何区分namedtuple仍然是更好解决方案的用例 数据类相对于NamedTuple的优势 当然,如果我们需要: 可变对象 继承支持 属性装饰器,可管理属性 即时生成的方法定义或可自定义的方法定义 同一PEP中简要说明了数据类的优势: 问:在哪种情况下,namedtuple仍然是更好的选择? 但是对于namedtuples,一个相反的问题是
collections.namedtuple
和typing.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
数据类方法:
from typing import NamedTuple
PageDimensions = NamedTuple("PageDimensions", [('width', int), ('height', int)])
from dataclasses import dataclass
@dataclass
class PageDimensions:
width: int
height: int
哪种解决方案更可取?为什么
另外,这个问题在任何方面都不是重复的,因为我在这里问的是命名双倍更好的情况,而不是差异(我在问之前检查了文档和源代码)在编程中,一般来说,任何可以不可变的东西都应该是不可变的。我们得到两件事:
您肯定是对的,数据类中存在重叠,特别是与
freezed=True
的重叠-但是仍然有一些特性,例如属于namedtuples的解包,并且总是不可变的-我怀疑他们是否会删除namedtuples,因为这取决于您的需要。他们每个人都有自己的好处
下面是对PyCon 2018上数据类的一个很好的解释
在Dataclass
中,所有实现都是用Python编写的,而在NamedTuple
中,所有这些行为都是免费的,因为NamedTuple
继承自tuple
。而且由于元组
结构是用C编写的,因此标准方法在命名元组(散列、比较等)中速度更快
还请注意,数据类
基于dict
,而命名元组
基于元组
。因此,使用这些结构有其优点和缺点。例如,使用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"))**
}
在哪些情况下,命名为tuple仍然是更好的选择
当您的数据结构需要/可以是不可变的、可散列的、可扩展的、可解包的、可比较的时,您可以使用NamedTuple
。如果您需要更复杂的东西,例如,数据结构继承的可能性,那么请使用Dataclass
我也有同样的问题,所以运行了一些测试并在这里记录了它们:
要点是namedtuple更适合于解包、爆炸和大小。Dataclass更快、更灵活
当您希望能够传递元组时,Namedtuple也非常适合于软键入。定义类型
class CircleArg(NamedTuple):
x: float
y: float
radius: float
然后将其解压缩到函数中。不要使用.attributes
,调用者将得到一个很好的“类型提示”,没有任何PITA
*focus, radius = circle_arg_instance (or tuple)
差异不是很大,我不会重构稳定的代码来从一个迁移到另一个。我已经看到了这个问题的可能重复,但对于主要问题没有答案:在哪些情况下命名的tuples仍然更适合使用?另请参见为什么不使用
@dataclass(freezed=True)的dataclass
?另一个优点是使用命名的元组进行解包-例如,如果我有一个点(x,y),我可以将其解包x,y=Point
-我想明确一点,尽管从某种意义上说你是对的-命名的元组是在python3之前创建的,这里显然有一点重叠。但因为它不是一个完全的替代品(解包,命名的耦合总是不可变的),它们可能不会删除namedtuples@maor10谢谢你的回答,现在我所看到的唯一优势就是打开行李。如上所述,数据类可以是不可变的。我认为您可以稍微重写一下答案,以便让其他人明白并接受它。似乎不变性本身不是问题所在,主要是关于解包。我同意这个答案。在我的例子中,如果可能的话,我通过键入使用NamedTuple,因为它可以被解包和传播。然而,在很多情况下,我需要一个数据类,通常是因为继承或自定义初始化。我发现有趣的是,dataclasses.dataclass
和collections.namedtuple
都只是代码生成器。面对面。对于collections.namedtuple
来说,它有一个巨大的模板字符串文本,可以获取exec
。我以为他们会以某种方式通过编程创建所有这些。但是代码生成然后执行是有意义的。FWIW,dataclasse