为什么Python数据类是装饰器而不是基类?

Giu*_*pox 6 python python-3.x

为什么 Python 实现dataclasses.dataclass为类装饰器而不是基类?我认为从概念的角度来看,将其作为基类至少会更清楚:该__init__方法似乎是数据类装饰器添加到类中的唯一内容,并且添加方法和属性是任何直接基类中的内容通常打算做。为什么要实现一个本质上修改类的装饰器?基类就是为此目的而设计的。此外,拥有“ Dataclass”基类将使用户更容易在需要任何特定工作机制时修改其行为,只需在继承数据类时覆盖基类的方法即可。

因为它显然是出于某种原因而这样做的,所以我试图找出原因。我想到的唯一的事情可能是一些与性能相关的事情,我认为继承一个类应该比通过函数传递一个类慢,但是我不确定数据类是否意味着高性能 - 也不是Python语言本身 - 无论如何我们都将其命名为元组

kay*_*ya3 5

数据类是在PEP 557中引入的,它描述了此功能的一些设计注意事项,包括被拒绝的想法。但是,没有提及使用装饰器的任何被拒绝的替代方案,例如使用基类代替。因此,对于为什么使用装饰器而不是基类,我们似乎无法给出明确的答案。也许使用基类根本不被视为一种选择。

也就是说,@dataclass装饰器只添加__init__方法的说法是不正确的。该dataclass函数的签名显示还提供了其他几个功能,您可以通过传递布尔标志来选择加入或退出:

  • __eq__,默认启用
  • __repr__,默认启用
  • 订购方式,例如__lt__,选择加入
  • __hash__, 选择参加
  • 通过__setattr____delattr__方法保持不变性,选择加入

原则上,这些方法可以在基类中以通用方式实现。然而,一旦已知现场规范,通过为这些方法生成代码就有可能获得更高的性能;这样,您就不必在每次方法调用时查看这些字段规范。(这些方法是在声明数据类时生成的,通过将 Python 代码构建为字符串并调用exec请参阅此处。)因此,使用装饰器的一大优点是您只需查看一次字段规范,然后生成代码该特定数据类。

通过类比,在基类中以通用方式实现这些就像解释一样,而使用装饰器生成代码就像编译一样。(当然,生成的代码仍然由 CPython 解释器解释,这就是为什么这只是一个类比。)

或者,换句话说,从基类继承诸如__eq____lt__和之类的方法意义不大__hash__,因为这些方法不会对每个数据类执行相同的操作,除非在更通用的意义上。