The CPython builtins min() and max() both return the first satisfactory object found. This behaviour is undocumented. Examining the source in bltinmodule.c shows that min() and max() both result in a call to min_max() with Py_LT and Py_GT passed respectively.
The behaviour of min() is correct. But with weak orderings of equivalent objects, surely max() should be using Py_GE ? (the converse of Py_LT). Should I be reporting a bug, submitting a patch, making feature request or suggesting a documentation update ? For a more mathematical consideration (not casual reading): Stepanov, Alexander and Paul McJones. 2009. Elements of Programming. Addison Wesley. Pages 52-53 The code below demonstrates the issue. Using the total key gives the correct result. Using the weak key returns the "incorrect" result. Tested with Python 2.7.1 and 3.1.2 (applies to 3.2) Stephen Evans from __future__ import print_function from operator import attrgetter class Pair(): def __init__(self, m0, m1): self.m0, self.m1 = m0, m1 # rich comparisons are not used def __lt__(self, other): raise NotImplementedError def __le__(self, other): raise NotImplementedError def __eq__(self, other): raise NotImplementedError def __ne__(self, other): raise NotImplementedError def __gt__(self, other): raise NotImplementedError def __ge__(self, other): raise NotImplementedError def __repr__(self): """repr() as a tuple""" return repr((self.m0, self.m1)) @property def total(self): return (self.m0, self.m1) @property def weak(self): return self.m0 def test(): """ demonstrate the failure of the builtin max() to respect the original order of equivalent objects. """ r = [ (0, 1), (0, 2) ] r = [ Pair(*p) for p in r ] # verify total and weak ordering assert r == sorted(r, key=attrgetter('weak')) == sorted(r, key=attrgetter('total')) print(r) # from the sorted list print(r[0], r[-1]) # using total ordering print(min(r, key=attrgetter('total')), max(r, key=attrgetter('total'))) # using weak ordering, builtin_min and builtin_max functions in bltinmodule.c # min works as expected using Py_LT # max uses Py_GT rather than the converse of Py_LT (which would be Py_GE) print(min(r, key=attrgetter('weak')), max(r, key=attrgetter('weak'))) test() -- http://mail.python.org/mailman/listinfo/python-list