tags:

views:

159

answers:

3

I'm seeking advice on doing the following in a more pythonic way.

Consider:

class MyObj(object):
    def __init__(self):
        self.dict_properties = {}

Suppose I've got a list which contains multiple MyObj instances:

mylist = [<__main__.MyObj object at 0x1005e3b90, ...]

Now i want to sort mylist based on the value of a certain key in dict_properties in MyObj.

What does work is:

mylist.sort(lambda x,y: cmp(x.dict_properties['mykey'],
                            y.dict_properties['mykey']))

but that hardly feels pythonic.

Is there a better way (perhaps using operator.attrgetter)?

+3  A: 

I'd just do:

mylist.sort(key=lambda o: o.dict_properties["kykey"])

You could also overide cmp on the class.

Alex Gaynor
Thanks a lot. I considered overriding cmp on the class but that would imply losing some of the dynamity of variably choosing 'mykey' (unless I'm wrong)
ChristopheD
+8  A: 
mylist.sort(key=lambda x: x.dict_properties['mykey'])

is way simpler, and faster. You could reach for operator and try to compose an attrgetter and an itemgetter, but a straightforward lambda (or def) seems simplest here.

Alex Martelli
Thanks a lot. Seems this is indeed a very clean way of providing this functionality ;-)
ChristopheD
Only negative point would be that this would not work below python 2.4, is it not? (although I doubt that there are still a lot of python installations around below that version).
ChristopheD
@ChristopheD, yep, `key=` was introduced in 2.4 (whose final release was a bit more than 5 years ago). Anybody who needs to support 6-year-old or older versions should no doubt be expected to mention that fact explicitly, I imagine;-).
Alex Martelli
What, a use for the evil, functional lambda construct?! Who would've thought?!
Omnifarious
@Omnifarious, `def` would do just as well (as I mention in the answer, of course) -- I guess doing more Javascript inclines me to see both `def` and `lambda` as ugly, silly, needlessly limiting spellings of `function`, anyway (Javascript has it just right in this one case!-).
Alex Martelli
+1  A: 

If speed is an issue, then use decorate-sort-undecorate:

    mylist_decorated = [(elem.dict_properties['mykey'], elem) for elem in mylist]
    mylist_decorated.sort()
    mylist = [elem[1] for elem in mylist_decorated] # or zip(*mylist_decorated)[1] :)
  • this way sort() can spread its wings.
Tomasz Zielinski
This is pretty much what the key parameter of the sort method does for you. If you are using Python < 2.4 then this would be a sensible way to do it, otherwise you are just making work for yourself.
Dave Kirby
Here you got me! Thank you for the tip.
Tomasz Zielinski