Oddity using sorted with key

Peter Otten __peter__ at web.de
Tue Mar 11 17:43:45 CET 2014

Josh English wrote:

> I am running into a strange behavior using the sorted function in Python

> print list(sorted(all_the_stuff, key=lambda x: x.name.lower))
> print list(sorted(all_the_stuff, key=lambda x: x.name.lower()))

Let's simplify your example some more:

>>> items = ["B", "2", "a"]
>>> sorted(items, key=lambda x: x.lower())
['2', 'a', 'B']

That certainly works. Let's have a look at the keys used for the sorting:

>>> for item in items:
...     print item, "-->", (lambda x: x.lower())(item)
B --> b
2 --> 2
a --> a

Now on to your first example. What are the keys in this case?

>>> for item in items:
...     print item, "-->", (lambda x: x.lower)(item)
B --> <built-in method lower of str object at 0x7fd7ae45d260>
2 --> <built-in method lower of str object at 0x7fd7ae3e40f8>
a --> <built-in method lower of str object at 0x7fd7ae43d648>

Just a bunch of bound methods. These compare by id(), basically the memory 
address of the bound method object, not something that makes a lot of sense 
as a sort key.

> 2.7. The key parameter is not behaving as the docs say it does:

You may be misled by the mention of key=str.lower

str.lower is an unbound method, and if you pass it to sorted() together with 
a list of strings, it results in a call

str.lower(item) # item is a string

which is equivalent to

item.lower() # item is a string

So while it doesn't work for a list of Thing instances, if you have bare 
strings you can do

>>> sorted(items, key=str.lower)
['2', 'a', 'B']

More information about the Python-list mailing list