]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-138991: Update dataclass documentation for new eq behavior in Python 3.13 (#139007)
authorAniket <148300120+Aniketsy@users.noreply.github.com>
Thu, 11 Jun 2026 17:15:29 +0000 (22:45 +0530)
committerGitHub <noreply@github.com>
Thu, 11 Jun 2026 17:15:29 +0000 (17:15 +0000)
And add tests.

Co-authored-by: Victor Stinner <vstinner@python.org>
Doc/library/dataclasses.rst
Lib/test/test_dataclasses/__init__.py

index 954edc4506df1a302fdf425e71f1636a0546852e..ce59d89843e761dc52afda7702521c9bf5f517d7 100644 (file)
@@ -100,12 +100,25 @@ Module contents
      ignored.
 
    - *eq*: If true (the default), an :meth:`~object.__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.
+     generated.
 
-     If the class already defines :meth:`!__eq__`, this parameter is
-     ignored.
+     This method compares the class by comparing each field in order. Both
+     instances in the comparison must be of the identical type.
+
+     If the class already defines :meth:`!__eq__`, this parameter is ignored.
+
+     .. versionchanged:: 3.13
+        The generated ``__eq__`` method now compares each field individually
+        (for example, ``self.a == other.a and self.b == other.b``), rather than
+        comparing tuples of fields as in previous versions.
+
+        This change makes the comparison faster but it may alter results in cases
+        where attributes compare equal by identity but not by value (such as
+        ``float('nan')``).
+
+        In Python 3.12 and earlier, the comparison was performed by creating
+        tuples of the fields and comparing them (for example,
+        ``(self.a, self.b) == (other.a, other.b)``).
 
    - *order*: If true (the default is ``False``), :meth:`~object.__lt__`,
      :meth:`~object.__le__`, :meth:`~object.__gt__`, and :meth:`~object.__ge__` methods will be
index 2468e3e64dd621c06a44f0cce3d8642145b7c6c7..423247c92ce3c293b8beec9a16c964615deae04f 100644 (file)
@@ -2792,6 +2792,55 @@ class TestEq(unittest.TestCase):
         self.assertEqual(C(1), 5)
         self.assertNotEqual(C(1), 1)
 
+    def test_eq_field_by_field(self):
+        @dataclasses.dataclass
+        class Point:
+            x: int
+            y: int
+
+        p1 = Point(1, 2)
+        p2 = Point(1, 2)
+        p3 = Point(2, 1)
+        self.assertEqual(p1, p2)
+        self.assertNotEqual(p1, p3)
+
+    def test_eq_type_check(self):
+        @dataclasses.dataclass
+        class A:
+            x: int
+
+        @dataclasses.dataclass
+        class B:
+            x: int
+
+        a = A(1)
+        b = B(1)
+        self.assertNotEqual(a, b)
+
+    def test_eq_custom_field(self):
+        class AlwaysEqual(int):
+            def __eq__(self, other):
+                return True
+
+        @dataclasses.dataclass
+        class Foo:
+            x: AlwaysEqual
+            y: int
+
+        f1 = Foo(AlwaysEqual(1), 2)
+        f2 = Foo(AlwaysEqual(2), 2)
+        self.assertEqual(f1, f2)
+
+    def test_eq_nan_field(self):
+        @dataclasses.dataclass
+        class D:
+            x: float
+
+        nan = float('nan')
+        d1 = D(nan)
+        d2 = D(nan)
+        self.assertNotEqual(d1, d2)
+
 
 class TestOrdering(unittest.TestCase):
     def test_functools_total_ordering(self):