Python神器函数sorted():3个您不得不看的特性
作为一种通用语言,Python已在各种学术和工业领域逐渐流行,用于科学计算,工程,Web开发和许多其他用途。 Python的一项引人入胜的功能是它是如此灵活,以至于同一功能可以有多个实现。让我们考虑以下简单的示例。
>>> # sort a list using sort() >>> names0 = ['Danny', 'Johnny', 'Billy', 'Donny'] >>> names0.sort() >>> names0['Billy', 'Danny', 'Donny', 'Johnny'] >>>>>> # sort a list using sorted() >>> names1 = ['Danny', 'Johnny', 'Billy', 'Donny'] >>> sorted(names1)['Billy', 'Danny', 'Donny', 'Johnny']>>>
[“比利”,“丹尼”,“唐尼”,“约翰尼”]
在上面的代码中,我们创建了两个列表:names0和names1,并使用sort()和sorted()函数分别对它们进行排序。显然,我们能够以相同顺序在列表中获得。
尽管sort()和sorted()函数之间的相似之处,但我想指出,几乎总是要使用sorted()而不是sort()。这是三个原因。
1. 与任何迭代器的兼容性
第一个原因是sorted()函数更灵活,因为它可以与任何可迭代对象一起使用。相比之下,sort()函数仅适用于列表。如果您不知道什么是可迭代的,可以参考下面的我的上一篇文章。简而言之,可迭代对象是可以在迭代中进行迭代的Python对象,例如元组,列表,集合和字典。
让我们根据兼容的数据类型比较sorted()和sort()。需要注意的一件事是,这两种功能的使用方式存在细微的差异。 sorted()函数将iterable作为参数,而sort()函数的调用者则使用点表示法调用该函数。
>>> # sort a tuple >>> _ = (3, 5, 4).sort() Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'tuple' object has no attribute 'sort' >>> _ = sorted((3, 5, 4)) >>>>>> # sort a dictionary>>> _ = {2: 'two', 0: 'zero', 1: 'one'}.sort() Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'dict' object has no attribute 'sort' >>> _ = sorted({2: 'two', 0: 'zero', 1: 'one'}) >>>>>> # sort a set >>> _ = set([2, 3, 4]).sort() Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'set' object has no attribute 'sort' >>> _ = sorted(set([2, 3, 4]))
如上面的代码所示,元组,字典和集合均无法调用sort()函数。实际上,sort()函数是列表对象的实例方法,而不是其他集合对象的实例方法,这意味着此函数仅可用于列表对象。相比之下,元组,字典和集合都可以通过sorted()函数进行排序,因为所有这些数据类型都是可迭代的,因此使其适合使用sorted()函数。
2. 创建列表的便利
第二个原因是sorted()函数将按所需顺序对可迭代对象进行排序后将返回一个列表对象。因此,这是构建新列表的便捷方法。但是,sort()函数会更改调用此方法的列表的顺序,我们称此顺序为就地排序。此外,此函数隐式返回None(有时,我们可以说,当隐式返回值为None时,它不返回任何内容)。
让我们考虑以下假设示例。我们从一个名为sales_dict的字典开始,该字典保存全年的销售记录。我们要根据销售额创建一个按降序排列的记录列表。
>>> # records of sales in a dictionary >>> sales_dict = {'Spring': 1000, 'Summer': 950, 'Fall': 1030, 'Winter': 1200} >>>>>> # create a list object of sales records >>> sales_list0 = sorted(sales_dict.items(), key=lambda x: x[1], reverse=True) >>> sales_list0[('Winter', 1200), ('Fall', 1030), ('Spring', 1000), ('Summer', 950)] >>>>>> sales_list1 = list(sales_dict.items())>>> sales_list1.sort(key=lambda x: x[1], reverse=True) >>> sales_list1[('Winter', 1200), ('Fall', 1030), ('Spring', 1000), ('Summer', 950)]
在上面的代码中,我们只需要使用sorted()函数编写一行代码即可获得所需的结果。但是,使用sort()函数,我们必须编写两行代码。值得注意的是,由于某人可能会误认为,我们无法通过使用点符号来组合这两行来生成所需的列表对象。
>>> # combine the two lines >>> sales_list2 = list(sales_dict.items()).sort(key=lambda x: x[1], reverse=True) >>> sales_list2>>> type(sales_list2) <class 'NoneType'> >>> print(sales_list2) None
如上面的代码所示,通过组合两行,我们得到的是None值。这是因为sort()函数的返回值为None,而不是调用该函数的列表对象。
3. 与迭代集成
由于sorted()函数返回列表,而sort()函数返回None,这种区别的含义是什么?好吧,在许多情况下,我们期望有可迭代对象,但没有NoneType对象。一种这样的场景是迭代,毕竟这是我们经常使用列表对象执行的一项关键操作。
考虑以下示例。我们有两个字典分别保存第一学期和第二学期的分数。目的是创建一个报告卡,总结每个学生的表现,并按姓名进行排序。
>>> # test results for the first semester >>> results1 = {'John': 95, 'Danny': 80, 'Zack': 98} >>>>>> # test results for the second semester >>> results2 = {'Danny': 84, 'Zack': 95, 'John': 88} >>>>>> # generate the report card>>> for name, score in sorted(results2.items()): ... print(f'{name} | Spring: {results1[name]} | Fall: {score}') ... Danny | Spring: 80 | Fall: 84 John | Spring: 95 | Fall: 88 Zack | Spring: 98 | Fall: 95
在上面的代码中,我们注意到这两个字典都没有期望的输出顺序,因此,我们将使用sorted()函数对字典进行排序。如您所见,我们可以将排序后的结果直接集成到for循环中,因为sorted()函数返回排序后的列表。
您可能已经预料到,如果我们在这种情况下尝试使用sort()函数,将会发生什么。请参阅下面的更多细节。
>>> for name, score in list(results2.items()).sort(): ... print(f'{name} | Spring: {results1[name]} | Fall: {score}') ... Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: 'NoneType' object is not iterable
总结
在本文中,我们讨论了为什么几乎应该始终使用sorted()函数而不是sort()函数的三个原因。
- sorted()函数更灵活,因为它可与任何可迭代对象一起使用,这与只适用于列表的sort()函数不同。
- sorted()函数是创建排序列表的便捷方法。
- sorted()函数可以方便地与迭代集成。
篇尾思考
最后但并非最不重要的一点是,您可能想知道何时应该考虑使用sort()函数。 对于这个问题,我没有确切的答案,但是我可以想到的一种情况是,当我们只处理列表对象而又不希望得到返回的列表时。 毕竟,sorted()函数将生成一个新列表,因此,当列表特别大时,使用sorted()函数创建新列表的内存使用效率不高。
考虑简单的例子。 我们需要对每个嵌套列表进行排序。 在某些情况下,列表可能非常大。 使用sort()函数只会对原始列表进行排序,从而避免创建不必要的新列表对象。
>>> # simplified nested lists; each list can be much larger >>> group_scores = [[7, 3, 5], [3, 2, 8], [9, 4, 5]] >>> for scores in group_scores: ... scores.sort() ... >>> group_scores[[3, 5, 7], [2, 3, 8], [4, 5, 9]]