Skip to main content

数据类dataclass

核心模块

Field

定义 对于常见和简单的用例,不需要其他功能。但是,有些数据类功能需要额外的每字段信息。为了满足这种对附加信息的需求,你可以通过调用提供的 field() 函数来替换默认字段值。

用法 提供了一个方法field(),如果通过调用 field() 指定字段的默认值,则该字段的类属性将替换为指定的 default 值。如果没有提供 default ,那么将删除类属性。目的是在 dataclass() 装饰器运行之后,类属性将包含字段的默认值,就像指定了默认值一样。

语法:

dataclasses.field(*, default=MISSING, default_factory=MISSING, repr=True, hash=None, init=True, compare=True, metadata=None)

MISSING 值是一个 sentinel 对象,用于检测是否提供了 default 和 default_factory 参数。 使用此 sentinel 是因为 None 是 default 的有效值。任何代码都不应直接使用 MISSING 值。

参数:

  • default :如果提供,这将是该字段的默认值。这是必需的,因为 field() 调用本身会替换一般的默认值。

  • default_factory :如果提供,它必须是一个零参数可调用对象,当该字段需要一个默认值时,它将被调用。除了其他目的之外,这可以用于指定具有可变默认值的字段,如下所述。 同时指定 defaultdefault_factory 将产生错误。

  • init :如果为true(默认值),则该字段作为参数包含在生成的 __init__() 方法中。

  • repr :如果为true(默认值),则该字段包含在生成的 __repr__() 方法返回的字符串中。

  • compare :如果为true(默认值),则该字段包含在生成的相等性和比较方法中( __eq__()__gt__() 等等)。

  • hash :这可以是布尔值或 None 。如果为true,则此字段包含在生成的 __hash__() 方法中。如果为 None (默认值),请使用 compare 的值,这通常是预期的行为。如果字段用于比较,则应在 hash 中考虑该字段。不鼓励将此值设置为 None 以外的任何值。

    设置 hash=Falsecompare=True 的一个可能原因是,如果一个计算 hash 的代价很高的字段是检验等价性需要的,但还有其他字段可以计算类型的 hash 。 即使从 hash 中排除某个字段,它仍将用于比较。

  • metadata :这可以是映射或 None 。 None 被视为一个空的字典。这个值包含在 MappingProxyType() 中,使其成为只读,并暴露在 Field 对象上。数据类根本不使用它,它是作为第三方扩展机制提供的。多个第三方可以各自拥有自己的键值,以用作元数据中的命名空间。

dataclass

传统数据类

反面教材:(来自官方SDK)

class Message:
def __init__(self, data=None):
self.id:str=""
self.name:str=""
self.guid_id:str=""
self...
if data:
self.__dict__ = data

反面教材是非常传统的写法,这样写的缺点非常多,而且每对应一个数据都要写一套,非常繁琐

方案1(不推荐,但比上面好)

因为需要用类来承载数据,所以对该数据就需要做一些第三方封装,以保证其数据可以做一些比较等常规操作

class Message:
def __init__(self, id:int, name:str, guid_id:str, ...):
self.__id = id # 使用双下划线,确保该数据不能被外部直接修改和访问,同时添加对应@property
self.__name = name
self.__gui_id = guid_id
...

@property
def self.id(self)->int: return self.__id
@property
def sefl.name(self)->str: return self.__name
...

# 直接被 print 打印时,输出的不再时无情的内存地址和对象名
def __repr__(self):
return f"{self.__class__.__name__}: id={self.id}, name={self.name}"

# 对象用 "==" 进行比较
def __eq__(self, other):
return (self.id, self.name, ...) === (other.id, other.name, ...)

# 首先判断两者是否继承自同一对象
if other.__class__ is self.__class:
return (self.id, self.name, ...) === (other.id, other.name, ...)
else:
# 让右边对象来调用 右边对象.__eq__(本对象)
return NotImplemented

# 对象用 "!=" 比较时
def __new__(self, other):
res = self.__eq__(other)
if res is NotImplemented:
return NotImplemented
else:
return not res

# 对象可序列化,同时需要添加访问函数和保护双下划线
def __hash__(self):
return bash((
self.__class__,
self.id,
self,name,
self...
))

# 让对象实现可被排序的功能
def __lt__(self, other):

def __le__(self, other):

def __gt__(self, other):

def __ge__(self, other):