不同的 dataclass 对象显示相等

Different dataclass object show equal

提问人:Vandit Goel 提问时间:10/9/2023 更新时间:10/9/2023 访问量:59

问:

我有一个简单的数据类,其中包含 3 个成员变量。当我为类创建两个不同的对象并检查是否相等时,即使成员变量的值不同,它也总是显示 True。

数据类:

@dataclass(init=False)
class DiagCodes:
    __slots__ = ["indx_nbr", "diag_cd", "diag_typ_cd"]

    def __init__(
        self,
        indx_nbr: Optional[int] = None,
        diag_cd: Optional[str] = None,
        diag_typ_cd: Optional[str] = None,
    ) -> None:

        self.indx_nbr = indx_nbr
        self.diag_cd = diag_cd
        self.diag_typ_cd = diag_typ_cd

if __name__ == "__main__":
    dc = DiagCodes(1)
    dc_empty = DiagCodes()

    print(dc == dc_empty)

输出:

对于数据类函数的默认实现,输出不应该显示为 false 吗?__eq__

我正在研究的 python 版本是 Python 3.8.10

蟒蛇 python-dataclasses

评论

2赞 Blckknght 10/9/2023
我很确定您的数据类没有任何可识别的字段,因此所有实例都是平等的。您需要将类型提示移动到类体中,而不仅仅是在签名中(从您显示的内容来看,您没有理由需要编写自己的方法)。__init____init__
0赞 Vandit Goel 10/9/2023
我编写了 init,以便可以为成员分配默认值。对于 python 3.8 中的插槽,在类中分配它们会产生错误。我真的很想使用插槽,因为我将创建数千个对象。

答:

2赞 Loocid 10/9/2023 #1

您并没有真正使用数据类的功能。数据类装饰器查找具有类型注释(称为字段)的类变量,而您没有这些变量。

数据类的默认值会比较其每个字段。由于您没有任何字段,因此相等返回 true。__eq__

请尝试以下操作(请注意,您可以删除 init=False 和手写的 __init__ 方法):

@dataclass(init=False)
class DiagCodes:
    __slots__ = ["indx_nbr", "diag_cd", "diag_typ_cd"]

    indx_nbr: Optional[int]
    diag_cd: Optional[int]
    diag_typ_cd: Optional[str]
    
    def __init__(
        self,
        indx_nbr: Optional[int] = None,
        diag_cd: Optional[str] = None,
        diag_typ_cd: Optional[str] = None,
    ) -> None:

        self.indx_nbr = indx_nbr
        self.diag_cd = diag_cd
        self.diag_typ_cd = diag_typ_cd

评论

0赞 Vandit Goel 10/9/2023
感谢您指出这一点。这奏效了!那么这是否意味着我必须在数据类中提及字段列表 4 次(slots、class variable、init args、params)?我真的很想使用插槽,因为我将创建数千个对象,而在 python 3.8 中,如果没有 init,我无法真正设置默认值。
0赞 Vandit Goel 10/9/2023
在代码中还有其他类似的类,它们最多可以有 100 个成员变量。因此,如果我不给出默认值,每次创建实例时,我都必须传递 100 个参数。有没有更好的设计方法?
0赞 Loocid 10/9/2023
“如果没有 init,我真的无法设置默认值。”您可以通过在字段上设置默认值来做到这一点。例如。这样一来,您应该能够删除并且只需要在两个地方使用您的成员。indx_nbr: Optional[int] = None__init__
0赞 Vandit Goel 10/9/2023
当我在字段上设置默认值时,出现此错误:ValueError:插槽中的“indx_nbr”与类变量冲突
0赞 Loocid 10/9/2023
啊对不起,我只是略过了,因为我以前从未使用过它。在 3.10 中,您可以在数据类装饰器中使用它来让它为您生成它。我不确定 3.8 的最佳解决方案是什么,或者是否有一个好的解决方案。__slots__slots=True