sort() vs sorted() in python – which one is better?

As a general-purpose language, Python has gradually gained popularity in various academic and industrial domains for scientific computation, engineering, web development, and many other usages. One fascinating feature of Python is that it’s so flexible that the same functionality can have more than one implementation. Let’s consider the trivial example below.

>>> # 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']

In the above code, we created two lists: names0 and names1 and used sort() and sorted() functions to sort them respectively. Apparently, we were able to obtain in the list in the same order.

Despite the similarity between sort() and sorted() functions for sorting, I would like to argue that it’s almost always true that you want to use sorted() instead of sort(). Here are three reasons.


1. Compatibility With Any Iterables

The first reason is that the sorted() function is more flexible in that it can work with any iterables. By contrast, the sort() function only works with lists. If you don’t know what iterables are, you can refer to my previous article below. Briefly, iterables are Python objects that can be iterated in iterations, such as tuples, lists, sets, and dictionaries.Understand Python’s Iterators and Iterables and Create Custom IteratorsIteration is one of the most important concepts in Python. Two terms that pertain to iteration are iterators and…medium.com

Let’s compare sorted() and sort() in terms of compatible data types. One thing to note that there is a subtle difference in how these two functions are used. The sorted() function takes the iterable as an argument, while the caller of the sort() function calls the function using the dot notation.

>>> # 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]))

As shown in the above code, none of tuples, dictionaries and sets are able to call the sort() function. In fact, the sort() function is an instance method of list objects but not other collection objects, which means that this function is only available to list-objects. By contrast, tuples, dictionaries, and sets can all be sorted by the sorted() function, as all of these data types are iterables, making them suitable to use the sorted() function.


2. Convenience in Creating Lists

The second reason is that the sorted() function will return a list object after sorting the iterable in the desired order. Thus, it’s a convenient way to build a new list. However, the sort() function changes the order of the list that calls this method, which we term as sorting in place. In addition, this function implicitly returns None (sometimes, we can say it doesn’t return anything when the implicit return value is None).

Let’s consider the following hypothetical example. We start with a dictionary called sales_dict, which holds sales records for the entire year. We want to create a list of sorted records in descending order according to the sales amount.

>>> # 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)]

In the above code, we only need to have one line of code using the sorted()function to achieve the desired result. However, using the sort() function, we have to write two lines of code. Notably, we can’t combine these two lines by using the dot notation to produce the desired list object, as someone may have mistakenly thought.

>>> # 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

As shown in the above code, by combining the two lines, what we get is a None value. It’s all because the return value of the sort() function is None, not the list object that calls the function.


3. Integration With Iteration

Since the sorted() function returns the list and the sort() function returns None, what’s the implication of this difference? Well, there are many scenarios where we expect to have iterables but not NoneType objects. One such scenario is iterations, which, after all, is one critical operation we often do with list-objects.

Consider the following example. We have two dictionaries that hold scores for the first and second semesters, respectively. The goal is to create a report card that summarizes each student’s performance that is sorted by the names.

>>> # 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

In the above code, we notice that neither dictionary has the desired order for our output, and thus we’ll use the sorted() function to sort the dictionary. As you can see, we can directly integrate the sorted result in the for-loop, because the sorted() function returns the sorted list.

You should probably have expected what will happen if we try to use the sort() function in this scenario. See below for more details.

>>> 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

Conclusion

In this article, we discussed three reasons why you should almost always use the sorted() function instead of the sort() function.

  • The sorted() function is more flexible because it works with any iterables, unlike the sort() function which only works with lists.
  • The sorted() function is a convenient way to create sorted lists.
  • The sorted() function can be conveniently integrated with iterations.