On 08.05.20 19:01, Steven D'Aprano wrote:
All this proposal adds is *duck-typing* to the comparison, for when
it doesn't matter what the container type is, you care only about the
values in the container. Why be forced to do a possibly expensive (and
maybe very expensive!) manual coercion to a common type just to check
the values for equality element by element, and then throw away the
coerced object?
If you have ever written `a == list(b)` or similar, then You Already
Needed It :-)
Initially I assumed that the reason for this new functionality was
concerned with cases where the types of two objects are not precisely
known and hence instead of converting them to a common type such as
list, a direct elementwise comparison is preferable (that's probably
uncommon though). Instead in the case where two objects are known to
have different types but nevertheless need to be compared
element-by-element, the performance argument makes sense of course.
So as a practical step forward, what about providing a wrapper type
which performs all operations elementwise on the operands. So for example:
if all(elementwise(chars) == string):
...
Here the `elementwise(chars) == string` part returns a generator which
performs the `==` comparison element-by-element.
This doesn't perform any length checks yet, so as a bonus one could add
an `all` property:
if elementwise(chars).all == string:
...
This first checks the lengths of the operands and only then compares for
equality. This wrapper type has the advantage that it can also be used
with any other operator, not just equality.
Here's a rough implementation of such a type:
import functools
import itertools
import operator
class elementwise:
def __init__(self, obj, *, zip_func=zip):
self.lhs = obj
self.zip_func = zip_func
def __eq__(self, other): return self.apply_op(other,
op=operator.eq)
def __lt__(self, other): return self.apply_op(other,
op=operator.lt)
... # define other operators here
def apply_op(self, other, *, op):
return self.make_generator(other, op=op)
def make_generator(self, other, *, op):
return itertools.starmap(op, self.zip_func(self.lhs, other))
@property
def all(self):
zip_func = functools.partial(itertools.zip_longest,
fillvalue=object())
return elementwise_all(self.lhs, zip_func=zip_func)
class elementwise_all(elementwise):
def apply_op(self, other, *, op):
try:
length_check = len(self.lhs) == len(other)
except TypeError:
length_check = True
return length_check and all(self.make_generator(other, op=op))
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at
https://mail.python.org/archives/list/python-ideas@python.org/message/CCPJWQ5TYCJHEUVZD554EEBYUIPIJIKP/
Code of Conduct: http://python.org/psf/codeofconduct/