Skip to content

Breaking change of dataclasses.dataclass comparison semantics in 3.13+ #128294

Open
@daskol

Description

@daskol

Bug report

Bug description:

Brief Description

Optimization done in #109870 changed semantic of dataclass comparison.

Description

The pseudo code below shows meaning of changes have been done in #109870. The semantic differs largely because of a shortcut in __eq__ implementation of sequence-like containers (see Objects/object.c). The shortcut essentially does self[i] is other[i]. Consequently, method __eq__ of self[i] is not evaluated for identical objects in 3.12 during dataclasses.dataclass comparison.

def __eq__312(self, other):
    return astuple(self) == astuple(other)

def __eq__313(self, other):
    for lhs, rhs in zip(astuple(self), astuple(other)):
        if not lhs == rhs:
            return False
    else:
        return True

According Python docs (citation below), v3.13 introduces breaking change since it does not consider fields as a tuples for dataclass comparison.

eq: If true (the default), an __eq__() method will be generated. This method compares the class as if it were a tuple of its fields, in order. Both instances in the comparison must be of the identical type.

Test Case

import numpy as np
from dataclasses import dataclass

@dataclass
class A:
    xs: np.ndarray

a = A(np.ones(3))
b = A(a.xs)

print(a == b)  # FAIL (3.13); OK (3.12).
# ValueError: Value The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

CPython versions tested on:

3.13 (3.12)

Operating systems tested on:

Linux

Metadata

Metadata

Assignees

Labels

3.13bugs and security fixes3.14bugs and security fixesstdlibPython modules in the Lib dirtopic-dataclassestype-bugAn unexpected behavior, bug, or error

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions