On Fri, May 8, 2020 at 8:38 PM Steven D'Aprano
On Fri, May 08, 2020 at 07:52:10PM +0200, Alex Hall wrote:
Would the proposal come with a new magic dunder method which can be overridden, or would it be like `is`?
An excellent question! I don't think there needs to be a dunder.
The problem with this to me (and I think it's part of what David and others are saying) is that you're proposing additional syntax (for which there's usually a high bar) for the marginal benefit of improving a very specific use case. For comparison, the recent `@` operator is also intended for a very specific use case (matrix multiplication) but it can at least be reused for other purposes by overriding its dunder method. On top of that, we can see very clearly how the arguments in Guido's essay on operators applied to this case, with clear examples in https://www.python.org/dev/peps/pep-0465/#why-should-matrix-multiplication-b.... That doesn't apply so well to .EQ. as using `==` twice in a single expression isn't that common, and any specific flavour like .EQ. is even less common. `list(a) == list(b)` or `sequence_equal(a, b)` is suboptimal for visual mental processing, but it's still fine in most cases. I would be more supportive of some kind of 'roughly equals' proposal (maybe spelt `~=`) which could be overridden and did sequence equality, case insensitive string comparison, maybe approximate float comparison, etc. But even that has marginal benefit and I agree with the objections against it, particularly having 3 operators with similar equalish meanings. Perhaps a better alternative would be the ability to temporarily patch `==` with different meanings. For example, it could be nice to write in a test: with sequence_equals(): assert f(x, y) == f(y, x) == expected instead of: assert list(f(x, y)) == list(f(y, x)) == list(expected) or similarly with equals_ignoring_order(), equals_ignoring_case(), equals_ignoring_duplicates(), equals_to_decimal_places(2), equals_to_significant_figures(3), etc. This could be especially nice if it replaced implicit uses of `==` deeper in code. For example, we were recently discussing this function: ``` def zip_equal(*iterables): sentinel = object() for combo in zip_longest(*iterables, fillvalue=sentinel): if sentinel in combo: raise ValueError('Iterables have different lengths') yield combo ``` `sentinel in combo` is worrying because it uses `==`. For maximum safety we'd like to use `is`, but that's more verbose. What if we could write: ``` def zip_equal(*iterables): sentinel = object() with is_as_equals(): for combo in zip_longest(*iterables, fillvalue=sentinel): if sentinel in combo: raise ValueError('Iterables have different lengths') yield combo ``` and under the hood when `in` tries to use `==` that gets converted into `is` to make it safe? That's probably not the most compelling example, but I'm sure you can imagine ways in which `==` is used implicitly that could be useful to override. I'm not married to this idea, it's mostly just fun brainstorming.