Python Simplified

Difference Between sort() and sorted() in Python

sort() and sorted() in Python

Introduction

How do you sort a list? You will be using either Python’s built-in sorted() function or the sort() method. But what is the difference between sort() and sorted()? Which one should you prefer and when? What happens under the hood, which runs faster, etc. In this article, we are going to answer your queries. So, let’s get started.

sort() vs sorted()

If you are eager to see details the below table summarizes all the differences between sort() and sorted(). We will going in details in rest of the article. So, don’t forget to go through the entire article.

difference between sort and sorted
Differences between sort() and sorted()

Syntax

The syntax for both sort() and sorted() is shown below. Note that / indicates the end of positional parameters, and * indicates the start of the keyword parameters. 

You may like our blog post here where parameters and arguments are explained in detail.

				
					sorted(iterable, /, *, key=None, reverse=False)

sort(*, key=None, reverse=False)
				
			

where
iterable: iterable such as list, tuple, set, dictionary, etc.
key: custom function to customize the sort order.
reverse: if set to True results in sorting in the descending order.

The main difference between sort() and sorted() is that the sorted() function takes any iterable (list, tuple, set, dictionary) and returns a new sorted object without affecting the original. On the other hand, sort() does in-place sorting meaning it won’t create a new list but updates the given list itself in the desired order (ascending or descending).

Refer to the below simple example using a list. As you can see sorted() returns a new object whereas sort() does an in-place sort operation. Also, sorting happens in ascending order by default. 

sort()

				
					>>> mylist = [5, 4, 3, 2, 1]

>>> mylist.sort()

>>> mylist
[1, 2, 3, 4, 5]
				
			

sorted()

				
					>>> mylist = [5, 4, 3, 2, 1]

>>> sorted(mylist)
[1, 2, 3, 4, 5]

>>> mylist
[5, 4, 3, 2, 1]

				
			

Not only list, but you can also sort any iterable tuple, list, and dictionaries using the sorted() function. Refer to the sample examples below. 

Sort example using dictionary: When you try to sort the dictionary objects, the sorting happens on the keys.

				
					>>> my_dict = {3:"Javascript", 2:"Java", 1: "Python"}
>>> sorted(my_dict)
[1, 2, 3]
				
			

Sort example using set: The below is an example of sorting the set object. 

				
					>>> my_set = set(["Python", "Java", "Javascript"])
>>> sorted(my_set)
['Java', 'Javascript', 'Python']
				
			

As you saw in the syntax above, both sort() and sorted() have two keyword-only arguments — key and reverse. Let’s understand these two parameters. Note that we will be looking at the examples using the sorted() function. But the same examples will be applicable to the sort() method as well but only on the lists.

Key Parameter

The key parameter takes a function or callable as its value which is then applied to each element before the sorting. Let’s look into some examples of how the key parameter can be used.

Example 1

When you try to sort a dictionary object, it will be sorted based on the dictionary keys by default as you saw in one of the previous examples. If you want to use dictionary values for sorting then the key parameter can be used as shown in the below example.  

				
					>>> my_dict = {"Javascript":2, "Python":1, "C":2}
>>> sorted(my_dict, key=lambda x: my_dict[x])
['Python', 'Javascript', 'C']
				
			

Example 2

Let’s say you have a list of strings and you want to sort based on the length of each string. To achieve this, you need to apply the len() function to each element in the list. The key=lambda x:len(x) does exactly the same. It calculates the length of each element before the sorting process and sorts based on the length of strings

				
					>>> my_list = ['Python', 'C', 'C++', 'Java', "Javascript"]
>>> sorted(my_list, key=lambda x: len(x))
['C', 'C++', 'Java', 'Python', 'Javascript']
				
			

Example 3

Here is another example. Say you have a class named Student with attributes name, grade, and marks. From the list of Student objects s1, s2, and s3, you can sort based on either name or grade, or marks.

				
					class Student:
    def __init__(self, name, grade, marks):
        self.name = name
        self.grade = grade
        self.marks = marks
        
    def __repr__(self):
        return repr((self.name, self.grade, self.marks))

s1 = Student('Chetan', 'C', 50)
s2 = Student('Swathi', 'A', 90)
s3 = Student('Megha', 'B', 70)

student_objects = [s1, s2, s3]
				
			

Sorting based on marks: The below code sorts based on the marks. Here we are passing the object’s named attribute marks i.e. st.marks to the key parameter. So that the sorting happens based on the marks. 

				
					>>> sorted(student_objects, key=lambda st:st.marks)
[('Megha', 'C', 50), ('Swathi', 'B', 70), ('Chetan', 'A', 90)]
				
			

Sorting based on grade: The below code sorts based on the grade instead of marks. Here we are passing the object’s named attribute grade i.e. st.grade to the key parameter. Now the sorting happens based on the grade.

				
					>>> sorted(student_objects, key=lambda st:st.grade)
[('Swathi', 'A', 90), ('Megha', 'B', 70), ('Chetan', 'C', 50)]
				
			

Example 4

Python’s operator module provides two methods itemgetter() and attrgetter() that can also be used in the key parameter. 

itemgetter example: The itemgetter fetches the item from its operand. In the below example, itemgetter(0) fetches name, itemgetter(1) fetches grade and itemgetter(2) fetches marks from student_tuples. Then the sorting happens based on what was used in the key parameter.

				
					>>> student_tuples = [('Chetan', 'C', 50),
                      ('Swathi', 'A', 90),
                      ('Megha', 'B', 70)]
                      
# sorts based on name
>>> sorted(student_tuples, key=itemgetter(0)) 
[('Chetan', 'C', 50), ('Megha', 'B', 70), ('Swathi', 'A', 90)]

# sorts based on grade
>>> sorted(student_tuples, key=itemgetter(1)) 
[('Swathi', 'A', 90), ('Megha', 'B', 70), ('Chetan', 'C', 50)]

# sorts based on marks
>>> sorted(student_tuples, key=itemgetter(2)) 
[('Chetan', 'C', 50), ('Megha', 'B', 70), ('Swathi', 'A', 90)]
				
			

attrgetter example: As the name says, it fetches the attribute from its operand. In the below example, attrgetter(0) fetches name, attrgetter(1) fetches grade and attrgetter(2) fetches marks. Then the sorting happens based on what you pass to the key parameter.

				
					>>> student_objects = [s1, s2, s3]

# sorts by name
>>> sorted(student_objects, key=attrgetter('name')) 
[('Chetan', 'C', 50), ('Megha', 'B', 70), ('Swathi', 'A', 90)]

# sorts by grade
>>> sorted(student_objects, key=attrgetter('grade')) 
[('Swathi', 'A', 90), ('Megha', 'B', 70), ('Chetan', 'C', 50)]

# sorts by marks
>>> sorted(student_objects, key=attrgetter('marks')) 
[('Chetan', 'C', 50), ('Megha', 'B', 70), ('Swathi', 'A', 90)]
				
			

Reverse Parameter

The reverse parameter is pretty straightforward to understand. By default, the sorting happens in ascending order (reverse=False). If you want to sort in descending order, you need to set reverse=True.

				
					>>> mylist = [5, 3, 1, 2, 4]

>>> sorted(mylist, reverse=False)
[1, 2, 3, 4, 5]

>>> sorted(mylist, reverse=True)
[5, 4, 3, 2, 1]
				
			

This is simplest example to show reverse parameter. You can try using this on all the examples we discussed in the above sections.

Natural ordering for a custom class

If you try to sort Student objects [s1, s2, s3] that we created earlier by passing the key parameter, you will run into TypeError as shown below. Because there is no natural ordering implemented for the Student Class. You can implement the natural ordering for custom classes using __lt__() or __gt__() dunder/special methods. (these are nothing but less than and greater than operations)

				
					>>> student_objects = [s1, s2, s3]
>>> sorted(student_objects)
				
			
				
					---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-141-a6e87c8cedd3> in <module>
----> 1 sorted(student_objects)

TypeError: '<' not supported between instances of 'Student' and 'Student'
				
			

In the modified version of the Student class below, we have added __lt__() method. As you can see, __lt__() method is implemented on the marks attribute of the class. So, with this code, when you try to sort student objects sorted(student_objects), it will be sorted based on the marks and you will not run into TypeError.

				
					class Student:
    def __init__(self, name, grade, marks):
        self.name = name
        self.grade = grade
        self.marks = marks
        
    def __repr__(self):
        return repr((self.name, self.grade, self.marks))
    
    def __lt__(self, other):
        return self.marks < other.marks

s1 = Student('Chetan', 'C', 50)
s2 = Student('Swathi', 'A', 90)
s3 = Student('Megha', 'B', 70)

student_objects = [s1, s2, s3]

sorted(student_objects)
				
			
				
					[('Chetan', 'C', 50), ('Megha', 'B', 70), ('Swathi', 'A', 90)]
				
			

What happens under the hood?

Let’s see this with an example mylist=[3, 2, 1, 5, 4]. When you call sorted(mylist), Python should compare the elements of the list before sorting. Right? So, how do you compare the elements? Using comparison operators > and < and these are implemented via dunder methods __lt__() and __gt__().

In this example, the elements of the list are integers and all integers are derived from the class ‘int’. If you check the output of dir(int) or dir(), you will notice that int class implements __gt__() and __lt__() methods. These are nothing but comparisons operators that are called comparing the elements during the sorting process.

Which is faster: sort() or sorted()

The sorted () function creates a copy of the object during the sort operation. This is additional overhead when compared to a sort() operation which is an in-place operation. Hence, sort() runs faster than sorted().

				
					# Speed using sorted() function
>>> nums = [random.random() for i in range(10_000_000)]
>>> timeit.timeit(stmt="sorted(nums)", globals=globals(), number=1)
9.425759500001732

# Speed using sort() method
>>> nums = [random.random() for i in range(10_000_000)]
>>> timeit.timeit(stmt="nums.sort()", globals=globals(), number=1)
8.331430700000055
				
			

When to use sort() and sorted()

  • If you need to mutate the list then consider using sort() otherwise use sorted()
  • If you want faster operation then consider using sort() as it is faster than sorted().

Conclusion

In this article, you have understood the differences and similarities between the sort() and sorted(). We looked into the syntax, how key and reverse parameters work. Then we saw an example on how to implement natural ordering for a custom class. We also saw that under the hood __gt__() and __lt__() methods are called during the sorting process. Finally, we ended our discussion that sort() is faster and when to use sort() and sorted().

References

Share on facebook
Share on twitter
Share on linkedin
Share on whatsapp
Share on email
Chetan Ambi

Chetan Ambi

A Software Engineer & Team Lead with over 10+ years of IT experience, a Technical Blogger with a passion for cutting edge technology. Currently working in the field of Python, Machine Learning & Data Science. Chetan Ambi holds a Bachelor of Engineering Degree in Computer Science.
Scroll to Top