当前位置: 首页 > 知识库问答 >
问题:

数据类与类型。命名了两个主要用例

燕富
2023-03-14

PEP-557在Python标准库中引入了数据类,基本上可以充当与< code > collections . named tuple 和< code>typing相同的角色。命名元组。现在我想知道如何区分命名元组仍然是更好的解决方案的用例。

当然,如果我们需要:

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

数据类的优点在同一个PEP中简要说明:为什么不直接使用命名。

但是对于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

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

另外,这个问题无论如何都不是那个问题的副本,因为我在这里问的是namedtuple更好的情况,而不是区别(我在问之前已经查看了文档和来源)

共有3个答案

邢英奕
2023-03-14

我也有同样的问题,所以做了一些测试,并记录在这里:https://shayallenhill.com/python-struct-options/

总结:

  • 命名图普尔更适合解压缩、分解和调整大小。
  • 数据类更快、更灵活。
  • 差异并不大,我不会重构稳定的代码来从一个移动到另一个。
  • NamedTuple 也非常适合软键入,当你希望能够传递元组时。

为此,请定义从其继承的类型。。。

class CircleArg(NamedTuple):
    x: float
    y: float
    radius: float

…然后将其解压缩到函数中。不要使用。attributes,您将得到一个很好的“类型提示”,而不需要为调用者提供任何PITA。

*focus, radius = circle_arg_instance  # or tuple
罗渝
2023-03-14

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

  1. 更容易阅读程序——我们不需要担心值会改变,一旦实例化,它就永远不会改变(namedtuple)
  2. 奇怪虫子的机会更少

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

我在评论中写了它,但我会在这里提到它:你绝对是对的,有一个重叠,特别是在数据类中冻结=True - 但仍然有一些功能,例如解压缩属于命名的tuples,它总是不可变的 - 我怀疑他们会删除这样的命名图普尔

汪凌
2023-03-14

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

以下是对2018年PyCon上的Dataclasses的一个很好的解释,Raymond Hettinger-Dataclasses:结束所有代码生成器的代码生成器

Dataclass中,所有实现都是用Python编写的,而在NamedTuple中,所有这些行为都是免费的,因为NamedTuple继承自tuple。而且因为tuple结构是用C编写的,所以标准方法NamedTuple(哈希、比较等)中更快。

另请注意,Dataclass基于dict,而NamedTupleNamedTuple基于tuple。因此,使用这些结构有优点也有缺点。例如,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。如果您需要更复杂的东西,例如,数据结构的继承可能性,那么请使用Dataclass

 类似资料:
  • 问题内容: 长话短说 PEP-557在Python标准库中引入了数据类,该类基本上可以充当和的角色。现在,我想知道如何将用例分隔,其中namedtuple仍然是更好的解决方案。 数据类优于NamedTuple 当然,如果需要,所有功劳都归功于: 可变对象 继承支持 装饰器,可管理的属性 现成的方法定义或可自定义的方法定义 在同一PEP中简要说明了数据类的优点:为什么不只使用namedtuple。

  • 泛型用于通常我们放置类型的位置,比如函数签名或结构体,允许我们创建可以代替许多具体数据类型的结构体定义。让我们看看如何使用泛型定义函数、结构体、枚举和方法,并且在本部分的结尾我们会讨论泛型代码的性能。 定义函数时可以在函数签名的参数数据类型和返回值中使用泛型。以这种方式编写的代码将更灵活并能向函数调用者提供更多功能,同时不引入重复代码。 回到 函数上,示例 10-4 中展示了两个提供了相同的寻找

  • time 包提供了时间的显示和计量用的功能。日历的计算采用的是公历。提供的主要类型如下: Location 代表一个地区,并表示该地区所在的时区(可能多个)。Location 通常代表地理位置的偏移,比如 CEST 和 CET 表示中欧。下一节将详细讲解 Location。 Time 代表一个纳秒精度的时间点,是公历时间。后面会详细介绍。 Duration 代表两个时间点之间经过的时间,以纳秒为单

  • 本文向大家介绍Java中int与integer的区别(基本数据类型与引用数据类型),包括了Java中int与integer的区别(基本数据类型与引用数据类型)的使用技巧和注意事项,需要的朋友参考一下 一、先说说int与integer的区别   int 是基本数据类型,默认值为0,不需要进行实例化   integer 是引用数据类型,是int的封装类型,默认值为null,创建该类型需要进行实例化。

  • 问题内容: 我在80多个不同的表中都有一个ReferenceIDvarchar(6)列。我需要在分配ID的政府组织实施更改之后,将其扩展到整个db的varchar(8)。 我希望声明一个游标以获取表名,如下所示: 然后按如下所示编辑类型: 之所以失败,是因为该列是某些表中主键的一部分(并且PK中包含的列因表而异)。 我真的不想不必为每个表手动删除并重新创建每个PK。 在游标中,有一种方法可以在更改

  • 我有一个对象,其中包含另一个对象类型的属性,我想将其视为复杂类型。 在添加迁移时,我遇到了需要主键的问题(这正是我想要防止的)。 实体类型坐标需要定义主键。 编辑 出于性能原因,我希望属性存储为和,而不是对另一个表的引用。