Python: sorted() vs list.sort()
Summary
其实这两个函数的区别看 help
就能看出很多:
>>> # Python 3.5.2
>>> help(sorted)
Help on built-in function sorted in module builtins:
sorted(iterable, key=None, reverse=False)
Return a new list containing all items from the iterable in ascending order.
A custom key function can be supplied to customise the sort order, and the
reverse flag can be set to request the result in descending order.
>>> # Python 3.5.2
>>> help(list.sort)
Help on method_descriptor:
sort(...)
L.sort(key=None, reverse=False) -> None -- stable sort *IN PLACE*
sorted()
的意思更像是sorted_list_from(x)
- 它可以用在任意的 iterable 上,比如:
- string
- tuple
- 虽然 tuple 是 immutable 的,但
sorted()
又不是 in-place 操作,所以无妨
- 虽然 tuple 是 immutable 的,但
- dict
- 返回的是 sorted keys
- generator
- 返回值一定是个新 list
- 它可以用在任意的 iterable 上,比如:
sort()
竟然是list
类型专属的 method,有点出乎我的意料- 它是 in-place 操作
- 号称是 stable 的但是我没有研究它具体是怎么实现的
这两个函数的 key
参数的用法是一样的,都应该是一个 function,表示用 key(x1) < key(x2)
而不是 x1 < x2
的关系来决定 x1, x2
的顺序。key = None
是应该是默认使用 x1.__lt__(x2)
Recipe 1: How to sort dict entries by keys?
这个 topic 有点微妙,因为我们一直强调的是 “dict
并不能保证 key
的 insertion order”,但这一点随着 python 的发展在发生变化。根据 Eugene Yarmash:
- Python 3.7+
- In Python 3.7.0 the insertion-order preservation nature of
dict
objects has been declared to be an official part of the Python language spec. Therefore, you can depend on it.
- In Python 3.7.0 the insertion-order preservation nature of
- Python 3.6 (CPython)
- As of Python 3.6, for the CPython implementation of Python, dictionaries maintain insertion order by default. This is considered an implementation detail though; you should still use
collections.OrderedDict
if you want insertion ordering that’s guaranteed across other implementations of Python.
- As of Python 3.6, for the CPython implementation of Python, dictionaries maintain insertion order by default. This is considered an implementation detail though; you should still use
- Python >=2.7 and <3.6
- Use the
collections.OrderedDict
class when you need adict
that remembers the order of items inserted.
- Use the
所以需要根据你使用的版本来决定你是该用 dict
还是 OrderedDict
:
# Python 3.5.2
x = {"cranberry": 99, "durian": 0, "apple":2, "banana": 3}
sorted_x = OrderedDict((key, x[key]) for key in sorted(x))
# OR
sorted_x = OrderedDict(sorted(x.items())) # Better!
注意 OrderedDict
的 __str__
和 __repr__
打印出来的 representation 和普通的 dict
不一样
>>> x
{'apple': 2, 'banana': 3, 'cranberry': 99, 'durian': 0}
>>> sorted_x
OrderedDict([('apple', 2), ('banana', 3), ('cranberry', 99), ('durian', 0)])
Recipe 2: How to sort a list of custom objects?
如果你有可以通用的 __lt__(self, other)
逻辑,可以去实现 __lt__(self, other)
。但要注意不要专门为了某一个特定的 sorting 的需求去写 __lt__(self, other)
。
class Student:
def __init__(self, name, grade, age):
self.name = name
self.grade = grade
def __lt__(self, other):
return self.grade < other.grade # Is this always the case?
更 general 的、不那么 invasive 的写法是用 key
参数:
sorted(student_objects, key=lambda student: student.grade)
from operator import itemgetter, attrgetter
sorted(student_tuples, key=itemgetter(1))
sorted(student_objects, key=attrgetter('grade'))
Comments