]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.15] gh-138991: Update dataclass documentation for new eq behavior in Python 3...
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Thu, 11 Jun 2026 17:45:30 +0000 (19:45 +0200)
committerGitHub <noreply@github.com>
Thu, 11 Jun 2026 17:45:30 +0000 (17:45 +0000)
gh-138991: Update dataclass documentation for new eq behavior in Python 3.13 (GH-139007)

And add tests.
(cherry picked from commit 402668b2b1a63a2b3cfd7a2ede07f6786f9beb8e)

Co-authored-by: Aniket <148300120+Aniketsy@users.noreply.github.com>
Co-authored-by: Victor Stinner <vstinner@python.org>
Doc/library/dataclasses.rst
Lib/test/test_dataclasses/__init__.py

index a09c28ad9791584dc994de39e0e032afe8d11d14..a77213af778ae6df8e2bb96aaab5d90ccba5152a 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 dcd6a3ef9abfab6e135bdd40678bc0e4243a1c39..cede6671da1475c1e4b45308696885d268a5f06f 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):