Table of Contents
- Introduction
- Lists: Mutable Sequences
- Tuples: Immutable Sequences
- Dictionaries: Key-Value Pairs
- Comparison: Lists vs. Tuples vs. Dictionaries
- Conclusion
- References
Lists: Mutable Sequences
Definition and Characteristics
A list is a mutable (changeable), ordered sequence of elements. Elements in a list can be of any data type (integers, strings, objects, even other lists) and can be duplicated. Lists are defined using square brackets [], with elements separated by commas.
Key Features:
- Mutable: Elements can be added, removed, or modified after creation.
- Ordered: Elements maintain their insertion order (as of Python 3.7+; earlier versions also preserved order for lists).
- Heterogeneous: Can contain elements of different data types.
- Dynamic: Automatically resizes as elements are added/removed.
Creating a List
Lists can be created in several ways:
-
Using square brackets:
fruits = ["apple", "banana", "cherry"] mixed_list = [1, "hello", 3.14, True, [4, 5]] # Heterogeneous elements empty_list = [] # Empty list -
Using the
list()constructor:
Converts iterable objects (e.g., strings, tuples) into lists:numbers = list(range(5)) # [0, 1, 2, 3, 4] string_list = list("python") # ['p', 'y', 't', 'h', 'o', 'n']
Accessing Elements in a List
Elements are accessed using indexing (for single elements) or slicing (for sub-sequences). Python uses zero-based indexing (the first element is at index 0).
Indexing:
fruits = ["apple", "banana", "cherry"]
print(fruits[0]) # Output: "apple" (first element)
print(fruits[-1]) # Output: "cherry" (last element, negative index)
Slicing:
Slicing extracts a sub-list using list[start:end:step], where:
start: Starting index (inclusive, default: 0).end: Ending index (exclusive, default: length of list).step: Interval between elements (default: 1).
numbers = [0, 1, 2, 3, 4, 5]
print(numbers[1:4]) # Output: [1, 2, 3] (elements from index 1 to 3)
print(numbers[:3]) # Output: [0, 1, 2] (from start to index 2)
print(numbers[::2]) # Output: [0, 2, 4] (every 2nd element)
print(numbers[::-1]) # Output: [5, 4, 3, 2, 1, 0] (reverse the list)
Modifying Lists
Since lists are mutable, you can modify elements, add new elements, or remove existing ones.
Adding Elements:
-
append(item): Addsitemto the end of the list.fruits = ["apple", "banana"] fruits.append("cherry") print(fruits) # Output: ["apple", "banana", "cherry"] -
extend(iterable): Adds all elements of an iterable (e.g., list, tuple) to the list.fruits = ["apple", "banana"] more_fruits = ["cherry", "date"] fruits.extend(more_fruits) print(fruits) # Output: ["apple", "banana", "cherry", "date"] -
insert(index, item): Insertsitemat the specifiedindex.fruits = ["apple", "cherry"] fruits.insert(1, "banana") # Insert "banana" at index 1 print(fruits) # Output: ["apple", "banana", "cherry"]
Removing Elements:
-
remove(item): Removes the first occurrence ofitem.fruits = ["apple", "banana", "banana", "cherry"] fruits.remove("banana") print(fruits) # Output: ["apple", "banana", "cherry"] -
pop(index): Removes and returns the element atindex(defaults to the last element if no index is given).fruits = ["apple", "banana", "cherry"] removed = fruits.pop(1) print(removed) # Output: "banana" print(fruits) # Output: ["apple", "cherry"] -
clear(): Removes all elements from the list.fruits = ["apple", "banana"] fruits.clear() print(fruits) # Output: []
Modifying Elements:
Reassign values using indexing:
numbers = [1, 2, 3]
numbers[1] = 20 # Change element at index 1 to 20
print(numbers) # Output: [1, 20, 3]
List Comprehensions
List comprehensions provide a concise way to create lists. They replace for-loops and are often more readable.
Syntax:
new_list = [expression for item in iterable if condition]
Examples:
-
Create a list of squares:
squares = [x**2 for x in range(5)] print(squares) # Output: [0, 1, 4, 9, 16] -
Filter even numbers:
numbers = [1, 2, 3, 4, 5, 6] evens = [x for x in numbers if x % 2 == 0] print(evens) # Output: [2, 4, 6]
Use Cases for Lists
- Storing dynamic collections (e.g., user inputs, sensor readings).
- When you need to modify elements (add/remove/update).
- Implementing stacks or queues (using
append()andpop()). - Temporary storage of data during processing.
Common Pitfalls with Lists
-
Modifying a list while iterating: This can cause unexpected behavior (e.g., skipping elements). Use a copy of the list instead:
numbers = [1, 2, 3, 4] # Bad: Modifying the list while iterating for num in numbers: if num % 2 == 0: numbers.remove(num) print(numbers) # Output: [1, 3] (unintended result: 4 is skipped) # Good: Iterate over a copy for num in numbers.copy(): if num % 2 == 0: numbers.remove(num) -
Shallow copies: Using
list.copy()or slicinglist[:]creates a shallow copy. Nested lists will still reference the original objects:original = [[1], [2]] shallow_copy = original.copy() shallow_copy[0][0] = 100 print(original) # Output: [[100], [2]] (original is modified!)
Tuples: Immutable Sequences
Definition and Characteristics
A tuple is an immutable (unchangeable), ordered sequence of elements. Like lists, tuples can contain heterogeneous elements and duplicates, but once created, their elements cannot be added, removed, or modified. Tuples are defined using parentheses (), though parentheses are optional in some cases.
Key Features:
- Immutable: Elements cannot be modified after creation.
- Ordered: Elements maintain insertion order (as of Python 3.7+).
- Heterogeneous: Supports mixed data types.
- Lightweight: More memory-efficient than lists (due to immutability).
Creating a Tuple
Tuples can be created in a few ways:
-
Using parentheses:
coordinates = (10, 20) mixed_tuple = (1, "hello", 3.14, [4, 5]) # Note: lists inside tuples are mutable! -
Without parentheses (tuple packing):
colors = "red", "green", "blue" # Parentheses omitted print(type(colors)) # Output: <class 'tuple'> -
Single-element tuples: Require a trailing comma to distinguish from a regular expression:
single_tuple = (5,) # Correct: tuple with one element not_a_tuple = (5) # Incorrect: type is int print(type(single_tuple)) # Output: <class 'tuple'> print(type(not_a_tuple)) # Output: <class 'int'> -
Using
tuple()constructor:tuple_from_list = tuple([1, 2, 3]) print(tuple_from_list) # Output: (1, 2, 3)
Accessing Elements in a Tuple
Like lists, tuples support indexing and slicing. Since tuples are immutable, you cannot modify elements, but you can access them.
Examples:
fruits = ("apple", "banana", "cherry")
print(fruits[1]) # Output: "banana" (indexing)
print(fruits[1:3]) # Output: ("banana", "cherry") (slicing)
print(fruits[-2:]) # Output: ("banana", "cherry") (negative slicing)
Why Use Tuples?
If tuples are immutable, why use them instead of lists?
- Immutability: Guarantees data integrity (e.g., configuration values that shouldn’t change).
- Performance: Tuples are faster to create and access than lists (since they don’t need to handle dynamic resizing).
- Dictionary keys: Tuples can be used as keys in dictionaries (lists cannot, because they’re mutable).
- Function returns: Functions often return tuples to return multiple values (e.g.,
divmod(5, 2)returns(2, 1)).
Tuple Packing and Unpacking
Tuple packing is creating a tuple by assigning multiple values to a single variable:
person = ("Alice", 30, "Data Scientist") # Packing
Tuple unpacking is extracting values from a tuple into separate variables:
name, age, profession = person # Unpacking
print(name) # Output: "Alice"
print(age) # Output: 30
print(profession) # Output: "Data Scientist"
Unpacking works with any iterable, not just tuples!
Use Cases for Tuples
- Storing fixed collections (e.g., days of the week, RGB color codes).
- Returning multiple values from a function.
- Using as keys in dictionaries (e.g.,
(x, y)coordinates as keys). - Ensuring data immutability (e.g., configuration settings).
Dictionaries: Key-Value Pairs
Definition and Characteristics
A dictionary (or dict) is a mutable, unordered (prior to Python 3.7) collection of key-value pairs. Each key maps to a value, allowing fast lookups, insertions, and deletions. Dictionaries are defined using curly braces {}, with keys and values separated by colons :, and pairs separated by commas.
Key Features:
- Mutable: Keys and values can be added, removed, or modified.
- Unordered (pre-Python 3.7): Insertion order was not preserved. As of Python 3.7+, dictionaries preserve insertion order.
- Key uniqueness: Keys must be unique; duplicate keys overwrite previous values.
- Hashable keys: Keys must be immutable (e.g., strings, numbers, tuples); lists cannot be keys.
Creating a Dictionary
Dictionaries can be created in several ways:
-
Using curly braces:
person = { "name": "Alice", "age": 30, "profession": "Data Scientist" } -
Using
dict()constructor:person = dict(name="Alice", age=30, profession="Data Scientist") -
From a list of tuples:
key_value_pairs = [("name", "Alice"), ("age", 30)] person = dict(key_value_pairs) print(person) # Output: {'name': 'Alice', 'age': 30}
Accessing Values in a Dictionary
Values are accessed using their keys. There are two common methods:
-
Direct key access:
person = {"name": "Alice", "age": 30} print(person["name"]) # Output: "Alice"⚠️ Warning: If the key does not exist, this raises a
KeyError. -
Using
dict.get(key, default):
Returnsdefault(orNoneif not specified) if the key does not exist:print(person.get("profession", "Unknown")) # Output: "Unknown" (key "profession" doesn't exist)
Other useful methods:
keys(): Returns a view object of all keys.values(): Returns a view object of all values.items(): Returns a view object of key-value pairs (tuples).
person = {"name": "Alice", "age": 30}
print(person.keys()) # Output: dict_keys(['name', 'age'])
print(person.values()) # Output: dict_values(['Alice', 30])
print(person.items()) # Output: dict_items([('name', 'Alice'), ('age', 30)])
Modifying Dictionaries
Dictionaries are mutable, so you can add, update, or remove key-value pairs.
Adding/Updating Keys:
Assign a value to a key (new keys are added; existing keys are updated):
person = {"name": "Alice", "age": 30}
person["profession"] = "Data Scientist" # Add new key
person["age"] = 31 # Update existing key
print(person) # Output: {'name': 'Alice', 'age': 31, 'profession': 'Data Scientist'}
Removing Keys:
-
del dict[key]: Deletes the key-value pair.del person["age"] print(person) # Output: {'name': 'Alice', 'profession': 'Data Scientist'} -
dict.pop(key, default): Removes and returns the value forkey(returnsdefaultif key not found).profession = person.pop("profession") print(profession) # Output: "Data Scientist" print(person) # Output: {'name': 'Alice'} -
dict.clear(): Removes all key-value pairs.
Dictionary Comprehensions
Like list comprehensions, dictionary comprehensions provide a concise way to create dictionaries.
Syntax:
new_dict = {key_expression: value_expression for item in iterable if condition}
Examples:
-
Create a dictionary of squares:
squares = {x: x**2 for x in range(5)} print(squares) # Output: {0: 0, 1: 1, 2: 4, 3: 9, 4: 16} -
Filter even keys:
numbers = {1: "one", 2: "two", 3: "three", 4: "four"} even_numbers = {k: v for k, v in numbers.items() if k % 2 == 0} print(even_numbers) # Output: {2: 'two', 4: 'four'}
Use Cases for Dictionaries
- Storing related data (e.g., user profiles with
name,email,age). - Fast lookups by key (average O(1) time complexity for access).
- Configuration settings (e.g.,
config = {"debug": True, "port": 8080}). - Counting occurrences (e.g., word frequencies in text).
Comparison: Lists vs. Tuples vs. Dictionaries
To help choose the right data structure, here’s a summary of their key differences:
| Feature | Lists | Tuples | Dictionaries |
|---|---|---|---|
| Mutability | Mutable | Immutable | Mutable |
| Order | Ordered (preserves insertion) | Ordered (preserves insertion) | Ordered (Python 3.7+); else unordered |
| Syntax | [element1, element2, ...] | (element1, element2, ...) | {key1: value1, key2: value2, ...} |
| Access Method | Index (e.g., list[0]) | Index (e.g., tuple[0]) | Key (e.g., dict["key"]) |
| Duplicates | Allowed | Allowed | Keys: No; Values: Yes |
| Use Case | Dynamic collections, modification | Fixed data, immutability | Key-value lookups, related data |
Conclusion
Lists, Tuples, and Dictionaries are foundational to Python programming. Each serves a unique purpose:
- Lists are ideal for dynamic, modifiable sequences.
- Tuples shine when immutability, speed, or hashability (as dictionary keys) is needed.
- Dictionaries excel at storing and retrieving data via unique keys.
By understanding their strengths and weaknesses, you’ll be able to write more efficient and readable code. Remember: the best data structure depends on your specific use case—ask yourself: Do I need to modify the data? Do I need fast lookups? Is order important?