Perceived inconsistency in py3k documentation
Peter Otten
__peter__ at web.de
Sun Dec 5 05:37:23 EST 2010
Greg wrote:
> This is my first post here, so if this is not the correct place to ask
> this, please direct me to the best place.
This is a good place to get general advice and to discuss potential bugs
when you are unsure whether they actually are bugs.
If you are sure that you ran into a bug in python or want to suggest an
improvement of the documentation where it is wrong or unclear or hard to
understand you can report to http://bugs.python.org .
> In looking at the py3k documentation for comparing two classes, two
> different view points are expressed (at least it seems so to me).
> 1) At http://docs.python.org/py3k/reference/datamodel.html:
> "There are no implied relationships among the comparison operators.
> The truth of x==y does not imply that x!=y is false. Accordingly, when
> defining __eq__(), one should also define __ne__()..."
> -- This seems to support the view that if in our code, we would like
> to use comparison operators <, >, =, !=, etc. then we should define a
> __lt__(), __gt__(), __eq__(), __ne__(), etc. for each comparison
> operator we would like.
>
> This appears to contrast
> 2) At http://docs.python.org/py3k/library/stdtypes.html:
> "Instances of a class cannot be ordered with respect to other
> instances of the same class, or other types of object, unless the
> class defines enough of the methods __lt__(), __le__(), __gt__(), and
> __ge__() (in general, __lt__() and __eq__() are sufficient, if you
> want the conventional meanings of the comparison operators)."
> -- This seems to imply that to get all of the operators, only
> __lt__() and __eq__() need to be defined (just __lt__() should suffice
> though I thought).
>
> So, which is it supposed to be? Or am I reading the documentation
> wrong?
I agree with you that the documentation is at least unclear. The following
experiment suggests that list.sort() works correctly if only __lt__() and
__eq__() are implemented which in my reading is what your second quote
intends to convey. But "enough of the methods..." is a fuzzy statement.
The other finding:
(1) a != b is emulated with not (a == b)
(2) a > b is emulated with b < a
is not something I'd expect after reading your first quote, but technically
(2) is covered by
"""... __lt__() and __gt__() are each other’s reflection ..."""
$ cat py3compare.py
report = True
class A:
def __init__(self, key, side="A"):
self.key = key
self.side = side
def __eq__(self, other):
result = self.key == other.key
if report:
print(self, "__eq__", other, "-->", result)
return result
def __lt__(self, other):
result = self.key < other.key
if report:
print(self, "__lt__", other, "-->", result)
return result
def __str__(self):
return "{}({})".format(self.side, self.key)
def __repr__(self):
return str(self.key)
a = A(1, "L")
for k in range(3):
b = A(k, "R")
print("{} != {}: {}\n".format(a, b, a != b))
print("{} > {}: {}\n".format(a, b, a > b))
print()
import random
items = []
for n in 10, 20:
items.extend(map(A, range(n)))
random.shuffle(items)
report = False
items.sort()
print(items)
print(a <= b)
$ python3 py3compare.py
L(1) __eq__ R(0) --> False
L(1) != R(0): True
R(0) __lt__ L(1) --> True
L(1) > R(0): True
L(1) __eq__ R(1) --> True
L(1) != R(1): False
R(1) __lt__ L(1) --> False
L(1) > R(1): False
L(1) __eq__ R(2) --> False
L(1) != R(2): True
R(2) __lt__ L(1) --> False
L(1) > R(2): False
[0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 11, 12, 13,
14, 15, 16, 17, 18, 19]
Traceback (most recent call last):
File "py3compare.py", line 39, in <module>
print(a <= b)
TypeError: unorderable types: A() <= A()
$
Conclusion: If you can come up with a text that is both correct and clear,
don't hesitate to tell us, here or on the bug tracker.
Peter
PS: The painless way out: always use @functools.total_ordering or the
equivalent cookbok recipe.
More information about the Python-list
mailing list