Skip to content

Commit 5bc2072

Browse files
miss-islingtonAniketsyvstinner
authored
[3.13] gh-138991: Update dataclass documentation for new eq behavior in Python 3.13 (GH-139007) (#151374)
gh-138991: Update dataclass documentation for new eq behavior in Python 3.13 (GH-139007) And add tests. (cherry picked from commit 402668b) Co-authored-by: Aniket <148300120+Aniketsy@users.noreply.github.com> Co-authored-by: Victor Stinner <vstinner@python.org>
1 parent c4f3d8c commit 5bc2072

2 files changed

Lines changed: 67 additions & 5 deletions

File tree

Doc/library/dataclasses.rst

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -103,12 +103,25 @@ Module contents
103103
ignored.
104104

105105
- *eq*: If true (the default), an :meth:`~object.__eq__` method will be
106-
generated. This method compares the class as if it were a tuple
107-
of its fields, in order. Both instances in the comparison must
108-
be of the identical type.
106+
generated.
109107

110-
If the class already defines :meth:`!__eq__`, this parameter is
111-
ignored.
108+
This method compares the class by comparing each field in order. Both
109+
instances in the comparison must be of the identical type.
110+
111+
If the class already defines :meth:`!__eq__`, this parameter is ignored.
112+
113+
.. versionchanged:: 3.13
114+
The generated ``__eq__`` method now compares each field individually
115+
(for example, ``self.a == other.a and self.b == other.b``), rather than
116+
comparing tuples of fields as in previous versions.
117+
118+
This change makes the comparison faster but it may alter results in cases
119+
where attributes compare equal by identity but not by value (such as
120+
``float('nan')``).
121+
122+
In Python 3.12 and earlier, the comparison was performed by creating
123+
tuples of the fields and comparing them (for example,
124+
``(self.a, self.b) == (other.a, other.b)``).
112125

113126
- *order*: If true (the default is ``False``), :meth:`~object.__lt__`,
114127
:meth:`~object.__le__`, :meth:`~object.__gt__`, and :meth:`~object.__ge__` methods will be

Lib/test/test_dataclasses/__init__.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2567,6 +2567,55 @@ def __eq__(self, other):
25672567
self.assertEqual(C(1), 5)
25682568
self.assertNotEqual(C(1), 1)
25692569

2570+
def test_eq_field_by_field(self):
2571+
@dataclasses.dataclass
2572+
class Point:
2573+
x: int
2574+
y: int
2575+
2576+
p1 = Point(1, 2)
2577+
p2 = Point(1, 2)
2578+
p3 = Point(2, 1)
2579+
self.assertEqual(p1, p2)
2580+
self.assertNotEqual(p1, p3)
2581+
2582+
def test_eq_type_check(self):
2583+
@dataclasses.dataclass
2584+
class A:
2585+
x: int
2586+
2587+
@dataclasses.dataclass
2588+
class B:
2589+
x: int
2590+
2591+
a = A(1)
2592+
b = B(1)
2593+
self.assertNotEqual(a, b)
2594+
2595+
def test_eq_custom_field(self):
2596+
class AlwaysEqual(int):
2597+
def __eq__(self, other):
2598+
return True
2599+
2600+
@dataclasses.dataclass
2601+
class Foo:
2602+
x: AlwaysEqual
2603+
y: int
2604+
2605+
f1 = Foo(AlwaysEqual(1), 2)
2606+
f2 = Foo(AlwaysEqual(2), 2)
2607+
self.assertEqual(f1, f2)
2608+
2609+
def test_eq_nan_field(self):
2610+
@dataclasses.dataclass
2611+
class D:
2612+
x: float
2613+
2614+
nan = float('nan')
2615+
d1 = D(nan)
2616+
d2 = D(nan)
2617+
self.assertNotEqual(d1, d2)
2618+
25702619

25712620
class TestOrdering(unittest.TestCase):
25722621
def test_functools_total_ordering(self):

0 commit comments

Comments
 (0)