[Tutor] Sorting Instance Attributes
Danny Yoo
dyoo@hkn.eecs.berkeley.edu
Thu Dec 12 13:17:08 2002
> 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"
This is pretty nice!
If we want to avoid using eval, we can still do something similar with
this:
###
def makeStudentComparer(attribute_name):
def comparison_function(a, b):
return cmp(getattr(a, attribute_name),
getattr(b, attribute_name))
return comparison_function
###
This function is unusual because it doesn't return a string or a number:
it actually returns a new comparison function that's custom-fitted to
compare what we want. If we want to mutter in intimidating technical
terms, we'd say makeStudentComparer returns a "closure". It's actually
not that scary: it's just a function that's dynamically generated, and
that knows about that 'attribute_name' that we originally passed in.
With this, we won't have a single global 'studentCompare()' function, but
we still have much of the power of your original code:
###
for currKey in ('id','firstName','lastName','grade'):
theClass.sort(makeStudentComparer(currKey))
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"
###
Good luck!