Skip to content

Inconsistent dataclass order behavior on Python 3.13+ #137658

Open

Description

@gesslerpd

Bug report

Bug description:

Semantics of dataclasses __eq__ have changed in Python 3.13+, the semantic is now inconsistent with the order=True generated set of dunder methods on the same Python 3.13+ versions.

Related issues:
#128294
#120645

@dataclasses.dataclass(order=True)
class Data:
    a: float

nan = float("nan")

assert not (Data(nan) < Data(nan))
# assert not (Data(nan) <= Data(nan)), "fails on 3.13 even though {<, ==} are both False"
assert not (Data(nan) > Data(nan))
# assert not (Data(nan) >= Data(nan)), "fails on 3.13 even though {>, ==} are both False"
assert (Data(nan) != Data(nan))
assert not (Data(nan) == Data(nan))

Proposed fix PR: #137497

CPython versions tested on:

3.13

Operating systems tested on:

Windows

Linked PRs

Activity

  1. ericvsmith commented on Sep 19, 2025

    @ericvsmith
    Member

    Can you please show code where the values of comparisons change as a result of this PR? I presume they're all NaN related, or values with equally wacky comparison methods. But I'd like any actual change in semantics to be noted.

  2. gesslerpd commented on Sep 24, 2025

    @gesslerpd
    ContributorAuthor

    @ericvsmith Yes related to weird NaN-like objects, in the example code above the commented out lines will fail. Added similar tests to the PR that pass for this scenario, but generally the PR writes the order methods in a way more consistent with the current accepted semantics of __eq__ after it was optimized.

    Ever since semantics of __eq__ changed in 3.13+ the order methods have still been using the direct tuple semantics causing a slight misalignment shown in this issue.

  3. DavidCEllis commented on Nov 10, 2026

    @DavidCEllis
    Contributor

    @ericvsmith is there a decision on whether we want to change this?

    It's not something that can be changed without also updating the documentation (as has been done for equality and which the current PR doesn't include) but is this something we want to do or should we close related issues?

    There is also a separate issue #144191 and PR #144222 to do a similar thing but only for classes with one field. However I think if we're going to do this we should do so for all dataclasses rather than special casing single field classes.

    I'm aware of 2 cases, both related to is not matching == whose behaviour would be modified by this change:

    1. Classes with specific instances that compare unequal to themselves, such as float("nan")
    2. Objects for which inst1 is inst2 is True but inst1 == inst2 or the subsequent conversion to boolean fails, like np.ndarray

    The first case is an observable difference, but one that would now match the new equality behaviour.

    For the second case, I don't think including fields that aren't orderable or comparable in a dataclass with order=True makes any sense but it is technically a change in behaviour.

    Behaviour demonstrations
    1. float("nan")
    from dataclasses import dataclass
    
    @dataclass(order=True)
    class Example:
        a: float
        b: float
    
    nan1 = float("nan")
    
    ex1 = Example(nan1, 3.14)
    ex2 = Example(nan1, 3.14)
    
    print(ex1 == ex2, ex1 > ex2, ex1 >= ex2)

    Main:

    False, False, True
    

    PR:

    False, False, False
    

    1. np.ndarray
    import numpy as np
    from dataclasses import dataclass
    
    @dataclass(order=True)
    class Example:
        a: np.ndarray
    
    ident_arr = np.ones(3)
    
    ex1 = Example(ident_arr)
    ex2 = Example(ident_arr)
    ex3 = Example(2 * np.ones(3))
    
    try:
        print(ex1 > ex2)
        print(ex1 >= ex2)
    except ValueError as e:
        print(repr(e))
    
    try:
        print(ex1 >= ex3)
    except ValueError as e:
        print(repr(e))

    3.15.2

    False
    True
    ValueError('The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()')
    

    PR Logic:

    ValueError('The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()')
    ValueError('The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()')
    
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    stdlibStandard Library Python modules in the Lib/ directorytopic-dataclassestype-bugAn unexpected behavior, bug, or error

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions