From af94789b6b0581327f88535f117a8f35a7df8bdb Mon Sep 17 00:00:00 2001 From: Tin Tvrtkovic Date: Sat, 20 Jul 2024 00:08:52 +0200 Subject: [PATCH 1/6] Speed up __eq__ --- src/attr/_make.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/attr/_make.py b/src/attr/_make.py index 097534fbb..dd76bfa71 100644 --- a/src/attr/_make.py +++ b/src/attr/_make.py @@ -1864,20 +1864,20 @@ def _make_eq(cls, attrs): globs = {} if attrs: lines.append(" return (") - others = [" ) == ("] for a in attrs: if a.eq_key: cmp_name = f"_{a.name}_key" # Add the key function to the global namespace # of the evaluated function. globs[cmp_name] = a.eq_key - lines.append(f" {cmp_name}(self.{a.name}),") - others.append(f" {cmp_name}(other.{a.name}),") + lines.append( + f" {cmp_name}(self.{a.name}) == {cmp_name}(self.{a.name})" + ) else: - lines.append(f" self.{a.name},") - others.append(f" other.{a.name},") - - lines += [*others, " )"] + lines.append(f" self.{a.name} == other.{a.name}") + if a is not attrs[-1]: + lines[-1] = f"{lines[-1]} and" + lines.append(" )") else: lines.append(" return True") From 15b9bcf3784144964a6259d53bea38da3f2c079c Mon Sep 17 00:00:00 2001 From: Tin Tvrtkovic Date: Sat, 20 Jul 2024 00:15:22 +0200 Subject: [PATCH 2/6] Changelog, disallow nans in tests --- changelog.d/1310.change.md | 1 + tests/strategies.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 changelog.d/1310.change.md diff --git a/changelog.d/1310.change.md b/changelog.d/1310.change.md new file mode 100644 index 000000000..62abe705c --- /dev/null +++ b/changelog.d/1310.change.md @@ -0,0 +1 @@ +Speed up the generated `__eq__` methods significantly. diff --git a/tests/strategies.py b/tests/strategies.py index cbbf5b334..cb3f326ea 100644 --- a/tests/strategies.py +++ b/tests/strategies.py @@ -75,7 +75,7 @@ def _create_hyp_nested_strategy(draw, simple_class_strategy): bare_attrs = st.builds(attr.ib, default=st.none()) int_attrs = st.integers().map(lambda i: attr.ib(default=i)) str_attrs = st.text().map(lambda s: attr.ib(default=s)) -float_attrs = st.floats().map(lambda f: attr.ib(default=f)) +float_attrs = st.floats(allow_nan=False).map(lambda f: attr.ib(default=f)) dict_attrs = st.dictionaries(keys=st.text(), values=st.integers()).map( lambda d: attr.ib(default=d) ) From abd2ed4856dd756a11822d2441a4d1938e3173e9 Mon Sep 17 00:00:00 2001 From: Tin Tvrtkovic Date: Sat, 20 Jul 2024 10:46:12 +0200 Subject: [PATCH 3/6] Fix `eq_key` comparisons --- src/attr/_make.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/attr/_make.py b/src/attr/_make.py index dd76bfa71..89c2d569f 100644 --- a/src/attr/_make.py +++ b/src/attr/_make.py @@ -1871,7 +1871,7 @@ def _make_eq(cls, attrs): # of the evaluated function. globs[cmp_name] = a.eq_key lines.append( - f" {cmp_name}(self.{a.name}) == {cmp_name}(self.{a.name})" + f" {cmp_name}(self.{a.name}) == {cmp_name}(other.{a.name})" ) else: lines.append(f" self.{a.name} == other.{a.name}") From d7164059578ce5afcb1bc308556dc5d5e24468a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tin=20Tvrtkovi=C4=87?= Date: Sat, 20 Jul 2024 13:15:49 +0200 Subject: [PATCH 4/6] Rework changlelog --- changelog.d/1310.breaking.md | 3 +++ changelog.d/1310.change.md | 1 - 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 changelog.d/1310.breaking.md delete mode 100644 changelog.d/1310.change.md diff --git a/changelog.d/1310.breaking.md b/changelog.d/1310.breaking.md new file mode 100644 index 000000000..e1627434d --- /dev/null +++ b/changelog.d/1310.breaking.md @@ -0,0 +1,3 @@ +Speed up the generated `__eq__` methods significantly by generating a chain of attribute comparisons instead of constructing and comparing tuples. +This change arguably makes the behavior more correct, +but changes it if an attribute compares equal by identity but not value, like `float('nan')`. \ No newline at end of file diff --git a/changelog.d/1310.change.md b/changelog.d/1310.change.md deleted file mode 100644 index 62abe705c..000000000 --- a/changelog.d/1310.change.md +++ /dev/null @@ -1 +0,0 @@ -Speed up the generated `__eq__` methods significantly. From 9e7fb4137645755258bc8b2440c4389a0ded4d16 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 20 Jul 2024 11:15:58 +0000 Subject: [PATCH 5/6] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- changelog.d/1310.breaking.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/changelog.d/1310.breaking.md b/changelog.d/1310.breaking.md index e1627434d..a8f0a7228 100644 --- a/changelog.d/1310.breaking.md +++ b/changelog.d/1310.breaking.md @@ -1,3 +1,3 @@ Speed up the generated `__eq__` methods significantly by generating a chain of attribute comparisons instead of constructing and comparing tuples. -This change arguably makes the behavior more correct, -but changes it if an attribute compares equal by identity but not value, like `float('nan')`. \ No newline at end of file +This change arguably makes the behavior more correct, +but changes it if an attribute compares equal by identity but not value, like `float('nan')`. From 828e0558b2a6828ee8c2496e21e11ed516905458 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tin=20Tvrtkovi=C4=87?= Date: Sat, 20 Jul 2024 13:22:01 +0200 Subject: [PATCH 6/6] Make docs more precise --- docs/comparison.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/comparison.md b/docs/comparison.md index 79786e9e1..7dd6ca581 100644 --- a/docs/comparison.md +++ b/docs/comparison.md @@ -5,7 +5,10 @@ For that, *attrs* writes `__eq__` and `__ne__` methods for you. Additionally, if you pass `order=True`, *attrs* will also create a complete set of ordering methods: `__le__`, `__lt__`, `__ge__`, and `__gt__`. -Both for equality and order, *attrs* will: +For equality, *attrs* will generate a statement comparing the types of both instances, +and then comparing each attribute in turn using `==`. + +For order, *attrs* will: - Check if the types of the instances you're comparing are equal, - if so, create a tuple of all field values for each instance,