Lists and tuples both store ordered sequences, but their mutability difference has significant implications for how and when you should use each.
Core Differences
| Feature | List [] |
Tuple () |
|---|---|---|
| Mutability | ✅ Changeable | ❌ Fixed after creation |
| Performance | Slower | Faster |
| Memory | More overhead | More compact |
| Hashable | ❌ No | ✅ Yes (if contents are) |
| Methods | Many (append, pop, sort...) | Few (count, index) |
When to Use Lists
Choose lists when your data needs to change:
cart = ["Apple", "Banana"]
cart.append("Orange")
cart.remove("Apple")
tasks = ["task1", "task2"]
current = tasks.pop(0)
results = []
for item in data:
if valid(item):
results.append(item)When to Use Tuples
Choose tuples for fixed, immutable data:
point = (10, 20)
origin = (0, 0)
red = (255, 0, 0)
blue = (0, 0, 255)
user = ("Alice", "alice@example.com", 30)
def get_dimensions():
return (1920, 1080)
width, height = get_dimensions()Tuples as Dictionary Keys
Since tuples are hashable, they work as dictionary keys:
locations = {
(40.7128, -74.0060): "New York",
(51.5074, -0.1278): "London",
(35.6762, 139.6503): "Tokyo"
}
print(locations[(40.7128, -74.0060)]) # "New York"
game_board = {
(0, 0): "player",
(1, 2): "enemy",
(3, 3): "treasure"
}The Single-Element Tuple Gotcha
Creating a single-element tuple requires a trailing comma:
not_a_tuple = (5)
print(type(not_a_tuple)) # <class 'int'>
single_tuple = (5,)
print(type(single_tuple)) # <class 'tuple'>
also_tuple = 5,
print(type(also_tuple)) # <class 'tuple'>Performance Comparison
Tuples have slight performance advantages:
Mempory Usage
Tuples consume less memory than lists because they are fixed in size and don't require extra space for dynamic resizing.
import sys
my_list = [1, 2, 3, 4, 5]
my_tuple = (1, 2, 3, 4, 5)
print(sys.getsizeof(my_list)) # 104 bytes
print(sys.getsizeof(my_tuple)) # 80 bytesCreation Speed
Creating tuples is slightly faster than creating lists because Python doesn't need to allocate extra memory for potential resizing.
import timeit
list_time = timeit.timeit('[1, 2, 3, 4, 5]', number=1_000_000)
tuple_time = timeit.timeit('(1, 2, 3, 4, 5)', number=1_000_000)
print("List creation time:", list_time)
print("Tuple creation time:", tuple_time)Output:
List creation time: 0.07529828699989594
Tuple creation time: 0.024285188999783713Named Tuples for Clarity
When tuples represent structured data, namedtuple improves readability:
from collections import namedtuple
Point = namedtuple('Point', ['x', 'y'])
User = namedtuple('User', ['name', 'email', 'age'])
p = Point(10, 20)
print(p.x, p.y) # 10 20
user = User("Alice", "alice@example.com", 30)
print(user.name) # "Alice"
x, y = p
print(p[0]) # 10Output:
10 20
Alice
10Mutability Nuance
Tuples are immutable, but mutable objects inside them can still change:
mixed = ([1, 2, 3], "hello")
mixed[0].append(4)
print(mixed) # ([1, 2, 3, 4], 'hello')Decision Guide
| Scenario | Best Choice |
|---|---|
| Data will be modified | List |
| Fixed configuration values | Tuple |
| Dictionary keys needed | Tuple |
| Function returning multiple values | Tuple |
| Building a collection dynamically | List |
| Representing a record/struct | Tuple (or namedtuple) |
Summary
- Lists: Mutable sequences for data that changes
- Tuples: Immutable sequences for fixed data, dictionary keys, and slight performance gains
Use tuples to signal "this data shouldn't change" and lists when modification is expected. When in doubt, consider whether you need to call append(), pop(), or similar methods, If not, a tuple may be the better choice.