Python Lists: An In-Depth Guide
Introduction
In Python, a list is a built-in data structure that is mutable, ordered, and allows duplicate elements. Lists are versatile and widely used for storing collections of items such as numbers, strings, or even other lists.
Table of Contents
What is a List?
A list in Python is an ordered collection of items (elements) that can be of any data type. Lists are defined by square brackets []
, and elements are separated by commas.
Example:
my_list = [1, "hello", 3.14, True]
Creating Lists
Empty List
empty_list = []
List with Elements
fruits = ["apple", "banana", "cherry"]
Using the list()
Constructor
numbers = list((1, 2, 3, 4))
Accessing List Elements
Indexing
Positive Indexing: Starts from
0
(first element).print(fruits[0]) # Output: apple
Negative Indexing: Starts from
-1
(last element).print(fruits[-1]) # Output: cherry
Slicing
print(fruits[0:2]) # Output: ['apple', 'banana']
- Syntax:
list[start:stop:step]
Modifying Lists
Changing an Element
fruits[1] = "blueberry"
print(fruits) # Output: ['apple', 'blueberry', 'cherry']
Adding Elements
Append: Adds an element to the end.
fruits.append("date")
Insert: Inserts an element at a specified position.
fruits.insert(1, "banana")
Removing Elements
Remove by Value:
fruits.remove("apple")
Remove by Index:
del fruits[0]
Pop: Removes and returns an element.
fruit = fruits.pop() # Removes last element
List Methods
Adding Elements
append(x)
: Add an item to the end.extend(iterable)
: Extend the list by appending elements from the iterable.fruits.extend(["elderberry", "fig"])
Removing Elements
remove(x)
: Remove the first occurrence of x.pop([i])
: Remove the item at the given position and return it.clear()
: Remove all items from the list.
Searching
index(x[, start[, end]])
: Return index of the first occurrence of x.count(x)
: Return the number of times x appears.
Sorting and Reversing
sort(key=None, reverse=False)
: Sort the items.reverse()
: Reverse the elements of the list.
Copying
copy()
: Return a shallow copy of the list.new_list = fruits.copy()
Iterating Over Lists
Using a for
Loop
for fruit in fruits:
print(fruit)
Using enumerate()
for index, fruit in enumerate(fruits):
print(index, fruit)
List Comprehensions
List comprehensions provide a concise way to create lists.
Syntax:
new_list = [expression for item in iterable if condition]
Example:
squares = [x**2 for x in range(1, 6)]
print(squares) # Output: [1, 4, 9, 16, 25]
Memory Allocation in Lists
Dynamic Array Implementation
Underlying Data Structure: Python lists are implemented as dynamic arrays (like vectors in C++ or ArrayList in Java).
Memory Over-allocation: When a list needs to grow beyond its current capacity, Python allocates more space than needed to reduce the number of reallocations.
Amortized Time Complexity: Appending to a list has an amortized time complexity of O(1) due to over-allocation.
How Memory is Allocated
Initial Allocation: When a list is created, it allocates space for a certain number of elements.
Resizing:
When the list exceeds its capacity, a new, larger block of memory is allocated.
The elements are copied to the new block.
The old block is deallocated.
Example of Memory Allocation:
import sys
my_list = []
print(sys.getsizeof(my_list)) # Initial size
for i in range(10):
my_list.append(i)
print(f"Length: {len(my_list)}, Size in bytes: {sys.getsizeof(my_list)}")
Explanation:
The
sys.getsizeof()
function shows the size of the list in bytes.As elements are appended, the size increases, but not necessarily with each append due to over-allocation.
Mutability of Lists
What Does Mutability Mean?
Mutable Objects: Can be changed after creation (e.g., lists, dictionaries).
Immutable Objects: Cannot be changed after creation (e.g., tuples, strings).
Why Lists are Mutable
In-Place Modifications: Lists allow you to modify elements, append, remove, or reorder without creating a new list.
Memory Efficiency: Modifying a list in place is more memory-efficient than creating a new list every time.
Why Lists are Mutable
Implementation Details
Direct Memory Access: Since lists are implemented as arrays, you can directly access and modify elements at specific indices.
No Need for Reallocation: For operations that don't exceed the current capacity, the underlying memory doesn't need to be reallocated.
Advantages of Mutability
Performance: Modifying elements in place is faster.
Flexibility: Easier to implement algorithms that require modification of data structures.
Examples and Use Cases
Example 1: Removing Duplicates from a List
original_list = [1, 2, 2, 3, 4, 4, 5]
unique_list = list(set(original_list))
print(unique_list) # Output: [1, 2, 3, 4, 5]
Example 2: Sorting a List of Strings
names = ["John", "Alice", "Bob"]
names.sort()
print(names) # Output: ['Alice', 'Bob', 'John']
Example 3: Filtering a List
numbers = [1, 2, 3, 4, 5]
even_numbers = [n for n in numbers if n % 2 == 0]
print(even_numbers) # Output: [2, 4]
Example 4: Nested Lists (2D Lists)
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
# Access element in row 2, column 3
print(matrix[1][2]) # Output: 6
Quick Revision Notes
List Creation
Empty List:
my_list = []
With Elements:
my_list = [element1, element2]
Accessing Elements
Indexing:
my_list[0]
,my_list[-1]
Slicing:
my_list[start:stop:step]
Modifying Lists
Change Element:
my_list[index] = new_value
Add Element:
append()
,insert()
,extend()
Remove Element:
remove()
,pop()
,del
List Methods
Adding:
append()
,extend()
,insert()
Removing:
remove()
,pop()
,clear()
Searching:
index()
,count()
Sorting:
sort()
,reverse()
Iteration
For Loop:
for item in my_list:
List Comprehension:
[expression for item in iterable]
Memory Allocation
Dynamic Arrays: Lists automatically resize as needed.
Over-allocation: Python allocates extra memory to minimize resizing operations.
Mutability
Lists are Mutable: You can modify them in place.
Advantages:
Performance: Faster modifications.
Memory Efficiency: Less memory overhead compared to creating new lists.
Important Points
Lists can contain mixed data types:
[1, "two", 3.0]
Nested Lists: Lists can contain other lists.
Copying Lists:
Shallow Copy:
new_list = old_list.copy()
Deep Copy: Use the
copy
module.
Conclusion
Python lists are a fundamental and powerful data structure that provides flexibility and efficiency. Understanding how lists work, including their memory allocation and mutability, allows you to write more efficient and effective Python code.
Practice Exercises:
Reverse a List Without Using Built-in Methods
def reverse_list(lst): return lst[::-1] # Test print(reverse_list([1, 2, 3])) # Output: [3, 2, 1]
Flatten a Nested List
nested_list = [[1, 2], [3, 4], [5, 6]] flat_list = [item for sublist in nested_list for item in sublist] print(flat_list) # Output: [1, 2, 3, 4, 5, 6]
Additional Resources:
Python Documentation on Lists: https://docs.python.org/3/tutorial/datastructures.html
Data Model: https://docs.python.org/3/reference/datamodel.html
Subscribe to my newsletter
Read articles from Sai Prasanna Maharana directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by