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
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):