[Tutor] Sorting Instance Attributes
Don Arnold
Don Arnold" <darnold02@sprynet.com
Wed Dec 11 22:43:02 2002
> > Hi all--
> >
> > I wrote a program awhile ago to help me keep track of
> > attendance in my courses. Now, as an exercise, I've
> > decided to rewrite the program OOP-style. Among other
> > things, each student will be an object. The Student
> > class constructor begins with this code:
> >
> > class Student:
> > def __init__(self, firstName, lastName):
> > self.firstName=firstName
> > self.lastName=lastName
> >
> > Adding a student into the course amounts to creating a
> > new instance of the Student class. Now, onto my
> > questions:
> >
> > 1. If I'd like to record most student information
> > within individual Student class instances, what would
> > be the recommended type (is that the right word?) to
> > use for storing the collection of Student objects?
> > List? Dictionary? I'll save the information via
> > cpickle or shelve.
>
> There is really no answer to this, depends on what you want to do with the
> "collection of Student objects." Think about how you want to manage this
> collection, what you want to do it. Is a list enough? Or probably it is
> better to roll out your own "collection" class?
>
> >
> > 2. [Here's the one that I'm stumped on...] How do I
> > sort objects via a single object attribute. In the
> > example above, suppose I'd like to create a class
> > list, sorted alphabetically via lastName?
>
> Here Python's magic methods are useful. Consider the following
>
> class Student(object):
>
> #Methods snipped.
>
> def __lt__(self, other):
> return self.lastname < other.lastname
>
> I have added here one magic method - magic methods are signalled by being
> surrounded by double underscores - that tells Python that this class
> understands what is "less than". The method code is really simple: Since
you
> want alphabetical order we can just delegate to the order of builtin
string
> objects (There are probably some caveats with uppercase letters but let us
> forget that for a moment). For more details on magic methods consult the
> manuals.
>
> Now, if you have a list, l say, of student objects, you can just call
>
> l.sort()
>
> and it will automatically sort the list by calling the __lt__ method.
>
> Pretty cool stuff, I say.
>
> >
> > As always, thanks for your help! -- Al Colburn
> >
>
> With my best regards,
> G. Rodrigues
>
This got me to thinking (which can be dangerous at times): what if you don't
always want to sort by the same attribute? I played around a little, and
here's what I came up with:
def setStudentKey(key):
"""builds the comparison function on the fly"""
c = 'def studentCompare(l,r):\n\treturn cmp(str(l.%s),str(r.%s))\n' \
% (key, key)
exec(c,__builtins__.__dict__)
class Student:
def __init__(self,id,firstName,lastName,grade):
self.id = id
self.firstName = firstName
self.lastName = lastName
self.grade = grade
if __name__ == '__main__':
theClass = []
Mary = Student(1,'Mary','Smith', 93)
Bob = Student(2,'Bob','Jones', 97)
John = Student(3,'John','Albert', 70)
theClass.append(Bob)
theClass.append(John)
theClass.append(Mary)
for currKey in ('id','firstName','lastName','grade'):
setStudentKey(currKey)
theClass.sort(studentCompare)
print 'class sorted by "%s":' % currKey
for x in theClass:
print '\t%s, %s, %s, %s' % (x.id,x.firstName,x.lastName,x.grade)
print "\n"
When ran, this outputs:
class sorted by "id":
1, Mary, Smith, 93
2, Bob, Jones, 97
3, John, Albert, 70
class sorted by "firstName":
2, Bob, Jones, 97
3, John, Albert, 70
1, Mary, Smith, 93
class sorted by "lastName":
3, John, Albert, 70
2, Bob, Jones, 97
1, Mary, Smith, 93
class sorted by "grade":
3, John, Albert, 70
1, Mary, Smith, 93
2, Bob, Jones, 97
I realize that it's not perfect, but I was still kind of proud of myself. Of
course, I then realized that I was probably re-inventing the wheel, so I
whipped out my copy of 'The Python Cookbook'. Sure enough, recipe 2.6
('Sorting a List of Objects by an Attribute of the Objects') had quite
elegantly beaten me to the punch. Oh, well!
Don