Python 3.7: Dataclasses 和 SimpleNameSpace 的效用

Python 3.7: Utility of Dataclasses and SimpleNameSpace

Python 3.7 提供了新的dataclasses,它具有预定义的特殊功能。

从总体上看,dataclassesSimpleNamespace 都提供了很好的数据封装工具。

@dataclass
class MyData:
    name:str
    age: int

data_1 = MyData(name = 'JohnDoe' , age = 23)

data_2 = SimpleNamespace(name = 'JohnDoe' , age = 23)

很多时候我使用 SimpleNamespace 只是为了包装数据并四处移动。

我什至将它子类化以添加特殊功能:

from types import SimpleNamespace

class NewSimpleNameSpace(SimpleNamespace):
    def __hash__(self):
        return some_hashing_func(self.__dict__)

对于我的问题:

  1. 人们如何在 SimpleNamespacedataclasses 之间做出选择?
  2. 当扩展 SimpleNamespace 可以达到相同的效果时,为什么需要它们?
  3. 所有其他用例 dataclasses 满足什么?

简短的回答是 PEP 557 涵盖了所有内容。把你的问题稍微打乱...

为什么?

  1. 利用 PEP 526 提供一种简单的方法来定义此类 classes。
  2. 支持静态类型检查器。

如何选择何时使用它们?

PEP 非常清楚它们不是替代品,并希望其他解决方案有自己的位置。

与任何其他设计决策一样,您因此需要准确确定您关心的功能。如果其中包括以下内容,您绝对不需要 dataclasses.

Where is it not appropriate to use Data Classes?

API compatibility with tuples or dicts is required. Type validation beyond that provided by PEPs 484 and 526 is required, or value validation or conversion is required.

也就是说,对于 SimpleNameSpace 也是如此,那么我们还能看什么来决定呢?让我们仔细看看 dataclasses...

提供的额外功能

现有的SimpleNameSpace定义如下:

A simple object subclass that provides attribute access to its namespace, as well as a meaningful repr.

python 文档继续说它提供了一个简单的 __init____repr____eq__ 实现。将此与 PEP 557 进行比较,dataclasses 还为您提供以下选项:

  • 排序 - 比较 class 就好像它是其字段的元组一样,按顺序。
  • 不变性 - 分配给字段会产生异常
  • 散列控制 - 尽管不推荐这样做。

很明显,如果您关心顺序或不变性(或需要小众散列控制),您应该使用数据classes。

其他用例?

我可以看到

None,尽管您可能会争辩说最初的 "why?" 涵盖了其他用例。

Dataclasses 更像 namedtuple 和流行的 attrs package than SimpleNamespace (which isn't even mentioned in the PEP)。它们有两个不同的预期目的。

数据classes

  • 结构化
  • 类型化(默认,但可选)
  • 为基本的 dunder 方法编写大部分样板(__init____hash____eq__ 等)
  • 为属性的默认值提供简单的机制
  • 可以轻松添加__slots__和方法

简单命名空间

  • "Grab bag"数据结构
  • 用于你需要的不仅仅是字典但又少于字典的地方 class
  • 不打算使用 __slots__

来自 SimpleNamespace 文档:

SimpleNamespace may be useful as a replacement for class NS: pass. However, for a structured record type use namedtuple() instead.

因为 @dataclass 应该替换 namedtuple 的很多用例,所以命名 records/structs 应该用 @dataclass 而不是 SimpleNamespace .

您可能还想看看 this PyCon talk by Raymond Hettinger,他在其中讲述了 @dataclass 的背景故事及其用途。