Rich Comparisons Gotcha
Steven D'Aprano
steve at REMOVE-THIS-cybersource.com.au
Sun Dec 7 09:44:55 EST 2008
On Sun, 07 Dec 2008 13:03:43 +0000, Rasmus Fogh wrote:
> Jamed Stroud Wrote:
...
>> Second, consider that any value in python also evaluates to a truth
>> value in boolean context.
But bool(x) can fail too. So not every object in Python can be
interpreted as a truth value.
>> Third, every function returns something.
Unless it doesn't return at all.
>> A function's returning nothing
>> is not a possibility in the python language. None is something but
>> evaluates to False in boolean context.
>
> Indeed. The requirement would be not that return_value was a boolean,
> but that bool(return_value) was defined and gave the correct result.
If __bool__ or __nonzero__ raises an exception, you would like Python to
ignore the exception and return True or False. Which should it be? How do
you know what the correct result should be?
>From the Zen of Python:
"In the face of ambiguity, refuse the temptation to guess."
All binary operators are ambiguous when dealing with vector or array
operands. Should the operator operate on the array as a whole, or on each
element? The numpy people have decided that element-wise equality testing
is more useful for them, and this is their prerogative to do so. In fact,
the move to rich comparisons was driven by the needs of numpy.
http://www.python.org/dev/peps/pep-0207/
It is a *VERY* important third-party library, and this was not the first
and probably won't be the last time that their needs will move into
Python the language.
Python encourages such domain-specific behaviour. In fact, that's what
operator-overloading is all about: classes can define what any operator
means for *them*. There's no requirement that the infinity of potential
classes must all define operators in a mutually compatible fashion, not
even for comparison operators.
For example, consider a class implementing one particular version of
three-value logic. It isn't enough for == to only return True or False,
because you also need Maybe:
True == False => returns False
True == True => returns True
True == Maybe => returns Maybe
etc.
Or consider fuzzy logic, where instead of two truth values, you have a
continuum of truth values between 0.0 and 1.0. What should comparing two
such fuzzy values for equality return? A boolean True/False? Another
fuzzy value?
Another one from the Zen:
"Special cases aren't special enough to break the rules."
The rules are that classes can customize their behaviour, that methods
can fail, and that Python should not try to guess what the correct value
should have been in the event of such a failure. Equality is a special
case, but it isn't so special that it needs to be an exception from those
rules.
If you really need a guaranteed-can't-fail[1] equality test, try
something like this untested wrapper class:
class EqualityWrapper(object):
def __init__(self, obj):
self.wrapped = obj
def __eq__(self, other):
try:
return bool(self.wrapped == other)
except Exception:
return False # or maybe True?
Now wrap all your data:
data = [a list of arbitrary objects]
data = map(EqualityWrapper, data)
process(data)
[1] Not a guarantee.
--
Steven
More information about the Python-list
mailing list