Python 数据类与typing.NamedTuple主要用例 长话短说

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,一个相反的问题是

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

数据类相对于NamedTuple的优势 当然,如果我们需要:

  • 可变对象
  • 继承支持
  • 属性
    装饰器,可管理属性
  • 即时生成的方法定义或可自定义的方法定义
同一PEP中简要说明了数据类的优势:

问:在哪种情况下,namedtuple仍然是更好的选择? 但是对于namedtuples,一个相反的问题是:为什么不使用dataclass呢? 我想从性能的角度来看,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
哪种解决方案更可取?为什么


另外,这个问题在任何方面都不是重复的,因为我在这里问的是命名双倍更好的情况,而不是差异(我在问之前检查了文档和源代码)

在编程中,一般来说,任何可以不可变的东西都应该是不可变的。我们得到两件事:

  • 更容易阅读程序-我们不需要担心值的变化,一旦实例化,它就永远不会改变(命名为tuple)
  • 不太可能有奇怪的虫子
  • 这就是为什么,如果数据是不可变的,那么应该使用命名元组而不是数据类

    我在评论中写道,但我会在这里提及:
    您肯定是对的,数据类中存在重叠,特别是与
    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