class my_class:
def __init__(self, attr1, attr2):
self.attr1 = attr1 #string
self.attr2 = attr2 #string
def __lt__(self, other):
if self.attr1 < other.attr1:
return True
else:
return self.attr2 < other.attr2
I will run into problems if attr1 or attr2 is None, and they
legitimately can be.
I know I can check for attr1 or attr2 or both being None and react
accordingly, but my real class has ten attributes and that approach will
be long. What are my alternatives?
This is a hard question to answer, because your code snippet isn't
clearly extensible to the case where you have ten attributes. What's the
rule for combining them? If instance A has five attributes less than
those of instance B, and five attributes greater than those of instance
B, which wins?
But if I had to guess an approach, I'd start with a helper function (or
method) that compares two raw values:
def compare(a, b):
"""Return -ve for less than, 0 for equal, +ve for greater than."""
if a is None:
return 0 if b is None else -1
if b is None:
return 1
return (b < a) - (a < b)
Now, in your class, you can use this helper function to check each
attribute in turn. Assuming that if an attribute is equal, you move on to
check the next one:
class MyClass:
def _compare(self, other):
for attr in 'attr1 attr2 attr3 attr4'.split():
a, b = getattr(self, attr), getattr(other, attr)
triflag = compare(a, b)
if triflag:
return triflag
return 0
def __lt__(self, other):
if not isinstance(other, MyClass):
return NotImplemented
return self._compare(other) < 0
def __eq__(self, other):
if not isinstance(other, MyClass):
return NotImplemented
return not self._compare(other)
def __ne__(self, other):
if not isinstance(other, MyClass):
return NotImplemented
return bool(self._compare(other))
and so on. You can save a certain amount of repetition (by my count, six
lines of code) by pulling out the "if not isinstance" check into a
decorator, but since the decorator is likely to be about six lines long,
I wouldn't bother