Module 5: Lists in Python
Lists are one of the most commonly used collection types in Python. They allow you to store multiple values inside a single variable and provide powerful operations for adding, removing, searching, sorting, and processing data.
For example, an application might use a list to store:
- Student names
- Product prices
- Shopping-cart items
- Exam marks
- User permissions
- API results
- Tasks
- File names
Unlike strings, Python lists are mutable, which means their contents can be changed after the list is created.
By the end of this module, you will be able to:
- Create and initialize Python lists
- Access elements using positive and negative indexes
- Modify list elements
- Slice lists
- Work with nested lists
- Add and remove elements
- Sort and reverse lists
- Copy lists correctly
- Search and count list elements
- Use list comprehensions
- Build practical list-based programs
- Avoid common list errors
What Is a List?
A list is an ordered, mutable collection of items.
Lists are created using square brackets [].
1fruits = ["Apple", "Banana", "Orange"] 2 3print(fruits)
Output:
1['Apple', 'Banana', 'Orange']
A list can contain zero or more elements.
1empty_list = [] 2 3print(empty_list)
Output:
1[]
Python lists maintain the order in which elements are inserted.
Why Use Lists?
Suppose you want to store the names of three students.
Without a list:
1student1 = "Ankit" 2student2 = "Rahul" 3student3 = "Aman"
This approach becomes difficult to manage as the number of students increases.
With a list:
1students = ["Ankit", "Rahul", "Aman"] 2 3print(students)
Now all student names are stored in one collection.
You can easily loop through them:
1students = ["Ankit", "Rahul", "Aman"] 2 3for student in students: 4 print(student)
Output:
1Ankit 2Rahul 3Aman
Lists are therefore useful whenever a program needs to work with a collection of related values.
Features of Python Lists
Python lists have several important characteristics.
Ordered
Items maintain their insertion order.
1numbers = [10, 20, 30] 2 3print(numbers)
Output:
1[10, 20, 30]
Mutable
You can change an existing element.
1numbers = [10, 20, 30] 2 3numbers[1] = 25 4 5print(numbers)
Output:
1[10, 25, 30]
Duplicate Values Are Allowed
1numbers = [10, 20, 20, 30] 2 3print(numbers)
Output:
1[10, 20, 20, 30]
Different Data Types Are Allowed
1data = ["Python", 100, 99.5, True] 2 3print(data)
Output:
1['Python', 100, 99.5, True]
Although Python allows mixed types, keeping related data in a consistent type often makes programs easier to understand and maintain.
Lists Can Contain Other Lists
1matrix = [ 2 [1, 2], 3 [3, 4] 4] 5 6print(matrix)
This creates a nested list.
1. Creating Lists
Empty List
1numbers = [] 2 3print(numbers)
Output:
1[]
An empty list is useful when you plan to add elements later.
1numbers = [] 2 3numbers.append(10) 4numbers.append(20) 5 6print(numbers)
Output:
1[10, 20]
List of Integers
1numbers = [10, 20, 30, 40] 2 3print(numbers)
List of Strings
1colors = ["Red", "Green", "Blue"] 2 3print(colors)
Mixed List
1data = ["Python", 25, True, 95.6] 2 3print(data)
Output:
1['Python', 25, True, 95.6]
Using the list() Constructor
Python provides the list() constructor for creating lists from iterable objects.
1letters = list("Python") 2 3print(letters)
Output:
1['P', 'y', 't', 'h', 'o', 'n']
You can also convert a range into a list:
1numbers = list(range(1, 6)) 2 3print(numbers)
Output:
1[1, 2, 3, 4, 5]
2. List Indexing
Each element in a list has an index.
Python uses zero-based indexing, so the first element is at index 0.
For example:
1Apple Banana Mango Orange 2 0 1 2 3
Accessing List Elements
1fruits = ["Apple", "Banana", "Mango", "Orange"] 2 3print(fruits[0]) 4print(fruits[2])
Output:
1Apple 2Mango
Modifying an Element
Because lists are mutable, you can change an element using its index.
1fruits = ["Apple", "Banana", "Mango", "Orange"] 2 3fruits[1] = "Pineapple" 4 5print(fruits)
Output:
1['Apple', 'Pineapple', 'Mango', 'Orange']
Negative Indexing
Negative indexes start from the end of the list.
1fruits = ["Apple", "Banana", "Mango", "Orange"] 2 3print(fruits[-1]) 4print(fruits[-2])
Output:
1Orange 2Mango
The last item is always available using:
1fruits[-1]
3. List Slicing
List slicing extracts a portion of a list.
The syntax is:
1list[start:end]
The start index is included, while the end index is excluded.
1numbers = [10, 20, 30, 40, 50] 2 3print(numbers[1:4])
Output:
1[20, 30, 40]
Slice from the Beginning
1numbers = [10, 20, 30, 40, 50] 2 3print(numbers[:3])
Output:
1[10, 20, 30]
Slice to the End
1print(numbers[2:])
Output:
1[30, 40, 50]
Copy a List Using Slicing
1numbers = [10, 20, 30] 2 3copy_of_numbers = numbers[:] 4 5print(copy_of_numbers)
This creates a new list containing the same elements.
Using a Step
The complete slicing syntax is:
1list[start:end:step]
Example:
1numbers = [10, 20, 30, 40, 50] 2 3print(numbers[::2])
Output:
1[10, 30, 50]
Reverse a List with Slicing
1numbers = [10, 20, 30, 40, 50] 2 3print(numbers[::-1])
Output:
1[50, 40, 30, 20, 10]
Slicing returns a new list; it does not change the original list.
4. Nested Lists
A list can contain other lists. Such a structure is called a nested list.
1matrix = [ 2 [1, 2, 3], 3 [4, 5, 6], 4 [7, 8, 9] 5] 6 7print(matrix)
You can access an inner list using two indexes.
1print(matrix[0][1])
Output:
12
The first index selects the row:
1matrix[0]
The second index selects an element inside that row:
1matrix[0][1]
Student Records Example
1students = [ 2 ["Ankit", 90], 3 ["Rahul", 85], 4 ["Aman", 88] 5] 6 7print(students[1][0]) 8print(students[2][1])
Output:
1Rahul 288
Nested lists can be useful for simple tabular data, although dictionaries or dedicated data structures may be better for complex records.
5. append()
The append() method adds one item to the end of a list.
1fruits = ["Apple", "Banana"] 2 3fruits.append("Orange") 4 5print(fruits)
Output:
1['Apple', 'Banana', 'Orange']
append() Adds One Element
This distinction is important:
1numbers = [1, 2] 2 3numbers.append([3, 4]) 4 5print(numbers)
Output:
1[1, 2, [3, 4]]
The entire [3, 4] list becomes one element.
6. extend()
The extend() method adds multiple elements from another iterable.
1numbers = [1, 2] 2 3numbers.extend([3, 4, 5]) 4 5print(numbers)
Output:
1[1, 2, 3, 4, 5]
append() vs extend()
1a = [1, 2] 2b = [3, 4] 3 4a.append(b) 5 6print(a)
Output:
1[1, 2, [3, 4]]
With extend():
1a = [1, 2] 2b = [3, 4] 3 4a.extend(b) 5 6print(a)
Output:
1[1, 2, 3, 4]
Think of it this way:
1append() → adds one object 2extend() → adds elements from an iterable
7. insert()
The insert() method adds an element at a specific index.
Syntax:
1list.insert(index, value)
Example:
1numbers = [10, 20, 40] 2 3numbers.insert(2, 30) 4 5print(numbers)
Output:
1[10, 20, 30, 40]
Insert at the Beginning
1numbers = [10, 20, 30] 2 3numbers.insert(0, 5) 4 5print(numbers)
Output:
1[5, 10, 20, 30]
If the index is larger than the list length, the element is inserted at the end.
8. remove()
The remove() method removes the first matching value.
1fruits = ["Apple", "Banana", "Orange"] 2 3fruits.remove("Banana") 4 5print(fruits)
Output:
1['Apple', 'Orange']
If the value occurs multiple times, only the first matching occurrence is removed.
1numbers = [10, 20, 20, 30] 2 3numbers.remove(20) 4 5print(numbers)
Output:
1[10, 20, 30]
Avoiding ValueError
Calling remove() for a value that does not exist raises a ValueError.
1fruits = ["Apple", "Banana"] 2 3if "Mango" in fruits: 4 fruits.remove("Mango") 5else: 6 print("Mango is not in the list")
Output:
1Mango is not in the list
9. pop()
The pop() method removes and returns an item.
Without an index, it removes the last item.
1numbers = [10, 20, 30, 40] 2 3removed = numbers.pop() 4 5print("Removed:", removed) 6print("Remaining:", numbers)
Output:
1Removed: 40 2Remaining: [10, 20, 30]
Remove an Item at a Specific Index
1numbers = [10, 20, 30, 40] 2 3removed = numbers.pop(1) 4 5print("Removed:", removed) 6print("Remaining:", numbers)
Output:
1Removed: 20 2Remaining: [10, 30, 40]
pop() is useful when you need both to remove an item and use the removed value.
10. sort()
The sort() method sorts a list in place.
1numbers = [5, 2, 8, 1] 2 3numbers.sort() 4 5print(numbers)
Output:
1[1, 2, 5, 8]
Descending Order
1numbers = [5, 2, 8, 1] 2 3numbers.sort(reverse=True) 4 5print(numbers)
Output:
1[8, 5, 2, 1]
Sorting Strings
1fruits = ["Orange", "Apple", "Banana"] 2 3fruits.sort() 4 5print(fruits)
Output:
1['Apple', 'Banana', 'Orange']
sort() vs sorted()
sort() modifies the original list:
1numbers = [3, 1, 2] 2 3numbers.sort() 4 5print(numbers)
sorted() returns a new sorted list:
1numbers = [3, 1, 2] 2 3sorted_numbers = sorted(numbers) 4 5print(sorted_numbers) 6print(numbers)
Output:
1[1, 2, 3] 2[3, 1, 2]
Use sorted() when you want to keep the original ordering unchanged.
11. reverse()
The reverse() method reverses the list in place.
1numbers = [1, 2, 3, 4] 2 3numbers.reverse() 4 5print(numbers)
Output:
1[4, 3, 2, 1]
reverse() vs [::-1]
1numbers = [1, 2, 3] 2 3reversed_numbers = numbers[::-1] 4 5print(reversed_numbers) 6print(numbers)
Output:
1[3, 2, 1] 2[1, 2, 3]
Slicing creates a new reversed list.
By contrast:
1numbers = [1, 2, 3] 2 3numbers.reverse() 4 5print(numbers)
changes the original list.
12. copy()
The copy() method creates a shallow copy of a list.
1a = [1, 2, 3] 2 3b = a.copy() 4 5print(a) 6print(b)
The two lists contain the same values, but they are separate list objects.
Why Is Copying Important?
Consider:
1a = [1, 2] 2 3b = a 4 5b.append(3) 6 7print(a)
Output:
1[1, 2, 3]
This happens because a and b refer to the same list.
Using copy():
1a = [1, 2] 2 3b = a.copy() 4 5b.append(3) 6 7print(a) 8print(b)
Output:
1[1, 2] 2[1, 2, 3]
Important Note About Shallow Copies
For a nested list, copy() copies only the outer list.
1a = [[1, 2], [3, 4]] 2b = a.copy() 3 4b[0].append(99) 5 6print(a) 7print(b)
The inner list is shared, so changing it affects both structures.
For deeply nested independent data, Python provides copy.deepcopy().
13. count()
The count() method returns the number of times a value appears.
1numbers = [1, 2, 2, 2, 3] 2 3print(numbers.count(2))
Output:
13
String example:
1fruits = ["Apple", "Banana", "Apple"] 2 3print(fruits.count("Apple"))
Output:
12
14. index()
The index() method returns the index of the first matching value.
1fruits = ["Apple", "Banana", "Orange"] 2 3print(fruits.index("Banana"))
Output:
11
If the value is not present, index() raises a ValueError.
A safer approach is:
1fruits = ["Apple", "Banana", "Orange"] 2 3if "Mango" in fruits: 4 print(fruits.index("Mango")) 5else: 6 print("Mango not found")
15. clear()
The clear() method removes all elements from a list.
1numbers = [1, 2, 3] 2 3numbers.clear() 4 5print(numbers)
Output:
1[]
The list itself still exists; it is simply empty.
Common List Methods
| Method | Description |
|---|---|
append() | Adds one item |
extend() | Adds multiple items |
insert() | Inserts an item at an index |
remove() | Removes the first matching value |
pop() | Removes and returns an item |
clear() | Removes all items |
copy() | Creates a shallow copy |
count() | Counts occurrences |
index() | Finds the first matching index |
sort() | Sorts the list in place |
reverse() | Reverses the list in place |
Useful Built-in Functions for Lists
Python also provides useful built-in functions for working with lists.
len()
Returns the number of elements.
1numbers = [10, 20, 30, 40] 2 3print(len(numbers))
Output:
14
sum()
Adds numeric elements.
1numbers = [10, 20, 30] 2 3print(sum(numbers))
Output:
160
min() and max()
1numbers = [10, 25, 5, 40] 2 3print(min(numbers)) 4print(max(numbers))
Output:
15 240
sorted()
Returns a new sorted list.
1numbers = [5, 2, 8, 1] 2 3result = sorted(numbers) 4 5print(result)
Output:
1[1, 2, 5, 8]
16. List Comprehension
A list comprehension provides a concise way to create a new list from an iterable.
Basic syntax:
1[expression for item in iterable]
Basic Example
1numbers = [x for x in range(5)] 2 3print(numbers)
Output:
1[0, 1, 2, 3, 4]
The equivalent traditional loop is:
1numbers = [] 2 3for x in range(5): 4 numbers.append(x) 5 6print(numbers)
List comprehension is useful when the transformation is simple and readable.
Creating Square Numbers
1squares = [x ** 2 for x in range(1, 6)] 2 3print(squares)
Output:
1[1, 4, 9, 16, 25]
Equivalent loop:
1squares = [] 2 3for x in range(1, 6): 4 squares.append(x ** 2)
Filtering Even Numbers
A condition can be added to a list comprehension.
Syntax:
1[expression for item in iterable if condition]
Example:
1evens = [x for x in range(1, 21) if x % 2 == 0] 2 3print(evens)
Output:
1[2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
Transforming Strings
1names = ["ankit", "rahul", "aman"] 2 3upper_names = [name.upper() for name in names] 4 5print(upper_names)
Output:
1['ANKIT', 'RAHUL', 'AMAN']
List Comprehension With Conditional Expressions
You can also use an if...else expression.
1numbers = [1, 2, 3, 4, 5] 2 3labels = [ 4 "Even" if number % 2 == 0 else "Odd" 5 for number in numbers 6] 7 8print(labels)
Output:
1['Odd', 'Even', 'Odd', 'Even', 'Odd']
Avoid making comprehensions unnecessarily complicated. If the logic becomes difficult to read, a normal for loop is usually better.
Practice Project 1: Shopping Cart
Problem
Create a shopping cart program that stores items and displays the cart contents and total number of items.
Basic Version
1cart = [] 2 3cart.append("Laptop") 4cart.append("Mouse") 5cart.append("Keyboard") 6 7print("Shopping Cart:") 8 9for item in cart: 10 print("-", item) 11 12print("Total Items:", len(cart))
Output:
1Shopping Cart: 2- Laptop 3- Mouse 4- Keyboard 5Total Items: 3
Interactive Version
1cart = [] 2 3while True: 4 item = input("Enter item (or 'done' to finish): ").strip() 5 6 if item.lower() == "done": 7 break 8 9 if item: 10 cart.append(item) 11 12print("\nShopping Cart:") 13 14for item in cart: 15 print("-", item) 16 17print(f"Total Items: {len(cart)}")
This example demonstrates:
- Empty lists
append()whileloopsstrip()lower()len()- Iterating through a list
Practice Project 2: Student Marks
Problem
Store marks for several subjects and calculate:
- Total marks
- Highest mark
- Lowest mark
- Average mark
Code
1marks = [] 2 3for i in range(5): 4 while True: 5 try: 6 mark = float(input(f"Enter marks for subject {i + 1}: ")) 7 8 if 0 <= mark <= 100: 9 marks.append(mark) 10 break 11 12 print("Enter a mark between 0 and 100.") 13 14 except ValueError: 15 print("Please enter a valid number.") 16 17total = sum(marks) 18average = total / len(marks) 19 20print("\nMarks:", marks) 21print("Total:", total) 22print("Highest:", max(marks)) 23print("Lowest:", min(marks)) 24print(f"Average: {average:.2f}")
This version also validates the input instead of assuming that the user always enters a valid number.
Practice Project 3: Remove Duplicates While Preserving Order
A common list-processing task is removing duplicate values.
Using set() is short:
1numbers = [1, 2, 2, 3, 4, 4, 5] 2 3unique = list(set(numbers)) 4 5print(unique)
However, a set-based approach should not be used when the original order matters.
A clear order-preserving solution is:
1numbers = [1, 2, 2, 3, 4, 4, 5] 2 3unique = [] 4 5for number in numbers: 6 if number not in unique: 7 unique.append(number) 8 9print(unique)
Output:
1[1, 2, 3, 4, 5]
For larger datasets, more efficient approaches using a set for membership tracking can be considered.
Additional Practice Exercises
Exercise 1: Find the Largest Number
1numbers = [15, 42, 8, 99, 23] 2 3print("Largest:", max(numbers))
Exercise 2: Find the Smallest Number
Create a program that finds the smallest value in:
1numbers = [15, 42, 8, 99, 23]
Hint:
1min(numbers)
Exercise 3: Search for an Item
1fruits = ["Apple", "Banana", "Orange"] 2 3item = input("Enter fruit: ").strip() 4 5if item in fruits: 6 print("Found") 7else: 8 print("Not Found")
Exercise 4: Merge Two Lists
1list1 = [1, 2, 3] 2list2 = [4, 5, 6] 3 4merged = list1 + list2 5 6print(merged)
Output:
1[1, 2, 3, 4, 5, 6]
Exercise 5: Reverse a List Without reverse()
1numbers = [10, 20, 30, 40] 2 3print(numbers[::-1])
Exercise 6: Find Even Numbers
Create a list containing all even numbers from 1 to 50 using list comprehension.
Expected pattern:
1[x for x in range(1, 51) if x % 2 == 0]
Exercise 7: Calculate Average
Given:
1marks = [80, 75, 90, 85, 95]
Calculate the average using:
1sum() 2len()
Common List Errors
1. Index Out of Range
Incorrect:
1numbers = [10, 20] 2 3print(numbers[5])
Error:
1IndexError: list index out of range
The valid positive indexes are only 0 and 1.
2. Removing a Value That Does Not Exist
1fruits = ["Apple", "Banana"] 2 3fruits.remove("Mango")
Error:
1ValueError: list.remove(x): x not in list
Check first when the value may not exist:
1if "Mango" in fruits: 2 fruits.remove("Mango")
3. Confusing append() and extend()
1numbers = [1, 2] 2 3numbers.append([3, 4]) 4 5print(numbers)
Output:
1[1, 2, [3, 4]]
If you need individual elements:
1numbers = [1, 2] 2 3numbers.extend([3, 4]) 4 5print(numbers)
Output:
1[1, 2, 3, 4]
4. Accidentally Sharing a List
Avoid assuming this creates an independent copy:
1a = [1, 2, 3] 2b = a
Both variables refer to the same list.
Use:
1b = a.copy()
when a separate shallow copy is required.
5. Modifying a List While Iterating
This can produce unexpected results:
1numbers = [1, 2, 3, 4, 5] 2 3for number in numbers: 4 if number % 2 == 0: 5 numbers.remove(number)
A safer approach is to create a new filtered list:
1numbers = [1, 2, 3, 4, 5] 2 3numbers = [number for number in numbers if number % 2 != 0] 4 5print(numbers)
Output:
1[1, 3, 5]
List vs String
Both lists and strings are sequences, so they support indexing and slicing.
However, there is an important difference:
| Feature | String | List |
|---|---|---|
| Stores | Characters/text | Any Python objects |
| Ordered | Yes | Yes |
| Mutable | No | Yes |
| Indexing | Yes | Yes |
| Slicing | Yes | Yes |
| Duplicate values | Yes | Yes |
| Can change individual elements | No | Yes |
Example:
1text = "Python" 2 3# Not allowed 4# text[0] = "J"
But with a list:
1languages = ["Python", "Java"] 2 3languages[0] = "C++" 4 5print(languages)
Output:
1['C++', 'Java']
Module Summary
In this module, you learned how Python lists work and why they are useful for storing collections of data.
The key concepts are:
- Lists are ordered collections.
- Lists are mutable.
- Lists allow duplicate values.
- Lists can contain different data types.
- Lists support positive and negative indexing.
- Slicing can extract portions of a list.
- Lists can contain other lists.
append()adds one item.extend()adds multiple elements.insert()adds an item at a specific position.remove()removes the first matching value.pop()removes and returns an item.sort()sorts a list in place.reverse()reverses a list in place.copy()creates a shallow copy.count()counts occurrences.index()finds the first matching index.clear()removes all elements.sorted()creates a new sorted list.- List comprehensions provide a concise way to create lists.
- Built-in functions such as
len(),sum(),min(), andmax()are useful for list processing.
Lists are fundamental to Python programming and will be used extensively when you learn loops, functions, dictionaries, file handling, APIs, data processing, and algorithms.
What's Next?
In the next module, you can learn about Python Tuples and understand how they differ from lists, when immutable collections are useful, and how tuple unpacking works.