builtin max() and weak ordering

S

Stephen Evans

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). ShouldI 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()
 
M

Mark Dickinson

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 ?

See:

http://bugs.python.org/issue9802

(and feel free to add comments to that issue).

Mark
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top