Why does min(A,B) behave different for lists and for classes?

R

Raymond Hettinger

Claudio said:
Is there any deeper reason I don't understand
explaining why does min(A,B) behave different
for classes than for lists?

Yes, the sort order for lists is determined by their contents. With
your example, the lists have identical contents, so min() returns the
first minimum value encountered which is A for min(A,B) and B for
min(B,A).

For instances, the sort order is determined by custom __cmp__ or rich
comparision methods. In the absence of those, the default ordering is
determined by the object's id. In your example, the default is used
and either object may be returned as the minimum depending on which
object id is a higher number (that is an implementation and state
dependent). Since the two objects have unique ids, min() will
consistently find one to be lower than the other irrespective of
argument order, if min(A,B) is A, then min(B,A) will also be A.

The best way to develop your understanding here is view the object ids
for the instances and experiment with the results of A<B, A<=B, A==B,
etc.

Then write a simple, pure python version of min() that returns the
first occurence of the lowest valued element. Trace through its
execution and all will become clear.


Raymond
 
C

Claudio Grondi

Trying to understand the outcome of the recent
thread (called later reference thread):

"Speed quirk: redundant line gives six-fold speedup"

I have put following piece of Python code together:

class PythonObject_class:
pass
PythonObject_class_instanceA = PythonObject_class()
PythonObject_class_instanceB = PythonObject_class()
PythonObject_list_instanceA = [1]
PythonObject_list_instanceB = [1]

print "min(A,B) is A: "
print "in case of classes as parameter: " +
str(min(PythonObject_class_instanceA, PythonObject_class_instanceB) is
PythonObject_class_instanceA)
print "in case of lists as parameter: " +
str(min(PythonObject_list_instanceA, PythonObject_list_instanceB) is
PythonObject_list_instanceA)
print "min(B,A) is A: "
print "in case of classes as parameter: " +
str(min(PythonObject_class_instanceB,
PythonObject_class_instanceA) is PythonObject_class_instanceA)
print "in case of lists as parameter: " +
str(min(PythonObject_list_instanceB,
PythonObject_list_instanceA) is PythonObject_list_instanceA)

getting as output:

min(A,B) is A:
in case of classes as parameter: True
in case of lists as parameter: True
min(B,A) is A:
in case of classes as parameter: True
in case of lists as parameter: False

Is there any deeper reason I don't understand
explaining why does min(A,B) behave different
for classes than for lists?
It makes for me currently not much sense how it
behaves for classes, because the result is according
to the postings in the above mentioned reference
thread nondeterministic.

Claudio
 
R

Raymond Hettinger

[Claudio Grondi]
The still open question for me then is:
Why does min() not raise an error in case
there is no comparison function definition
for the feeded objects available?

Actually, there is a comparison function for
class instances. Unfortunately, the default
method is not very useful in your case. It
works a bit like this:

def __cmp__(self, other):
return cmp(id(self), id(other))

This is mildly useful as it allows distinct
objects to have an ordering relation.


Raymond
 
C

Claudio Grondi

Thanks to Raymond for his reply.

If I understand him right, there is no problem with
min() as such, but with the definition of the class, which
when used in min() should define at least __cmp__().

I have attached code with another
class PythonObject_classWithDefined__cmp__:
where the behaviour of min() is like I would
expect it.

Using classes without defined __cmp__ in comparison
operations violates the directive:
"Explicit is better than implicit"
and is just to be considered bad programming
style or to name it more directly, just a way of
obfuscating code, right?

The still open question for me then is:
Why does min() not raise an error in case
there is no comparison function definition
for the feeded objects available?

Claudio

ATTACHMENT:

class PythonObject_classWithDefined__cmp__:
def __init__(self, value = 1):
self.value = value
#:def
def __cmp__(self, otherInstance):
if ( self.value < otherInstance.value ):
return -1
elif(self.value == otherInstance.value ):
return 0
else:
return 1
#:if/else
#:def
#:class

PythonObject_classWithDefined__cmp__instanceA =
PythonObject_classWithDefined__cmp__()
PythonObject_classWithDefined__cmp__instanceB =
PythonObject_classWithDefined__cmp__()
print "min(A,B) is A: "
print "in case of classes with defined __cmp__() as parameter: " +
str(min(PythonObject_classWithDefined__cmp__instanceA,
PythonObject_classWithDefined__cmp__instanceB) is
PythonObject_classWithDefined__cmp__instanceA)
print "min(B,A) is A: "
print "in case of classes with defined __cmp__() as parameter: " +
str(min(PythonObject_classWithDefined__cmp__instanceB,
PythonObject_classWithDefined__cmp__instanceA) is
PythonObject_classWithDefined__cmp__instanceA)

outputs:

min(A,B) is A:
in case of classes with defined __cmp__() as parameter: True
min(B,A) is A:
in case of classes with defined __cmp__() as parameter: False
 

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,754
Messages
2,569,521
Members
44,995
Latest member
PinupduzSap

Latest Threads

Top