Tuple vs List
Comprehensive Comparison
Key differences between tuples and lists:
- **Mutability**: Lists can change, tuples cannot
- **Memory**: Tuples are generally more memory efficient than lists for the same elements
- **Performance**: Tuples often have faster creation; random access is O(1) for both
- **Methods**: Lists provide many mutating methods; tuples intentionally have few
- **Use Cases**: Lists for dynamic, growable data; tuples for fixed records/coordinates/return-values
- **Hashability**: Tuples can be dictionary keys **if all their elements are hashable**
# Memory comparison
import sys
lst = [1, 2, 3, 4, 5]
tpl = (1, 2, 3, 4, 5)
print(f"List size: {sys.getsizeof(lst)} bytes")
print(f"Tuple size: {sys.getsizeof(tpl)} bytes")
# Method availability
print("\nList methods:", dir(lst))
print("\nTuple methods:", dir(tpl))
# Hashability test
try:
{lst: "value"}
except TypeError as e:
print(f"\nList hash error: {e}")
print("Tuple as key:", {tpl: "valid"})
# A tuple is unhashable if it contains unhashable elements (e.g., a list)
# unhashable_tpl = (1, [2, 3]) # Would raise: TypeError: unhashable type: 'list'
List size: 96 bytes Tuple size: 80 bytes List methods: ['__add__', '__class__', ...] Tuple methods: ['__add__', '__class__', ...] List hash error: unhashable type: 'list' Tuple as key: {(1, 2, 3, 4, 5): 'valid'}
When to Use Each
Situation | Recommended Type | Reason |
---|---|---|
Data that changes frequently | List | Mutable |
Dictionary keys | Tuple | Hashable (if elements are hashable) |
Function arguments | Tuple | Immutable safety |
Large read-only datasets | Tuple | Memory efficiency |
Stack/queue operations | List | append/pop methods |
Configuration constants | Tuple | Prevents modification |
Multiple return values | Tuple | Lightweight packing |
Conversion Patterns
Converting between tuples and lists:
- **tuple()**: Converts any iterable to tuple
- **list()**: Converts any iterable to list
- **Performance**: Conversion has O(n) time complexity and allocates new storage
- **Use Cases**: Temporary conversion for modification or for hashing/caching
# Conversion examples
from timeit import timeit
lst = [1, 2, 3]
tpl = (4, 5, 6)
# List to tuple
new_tuple = tuple(lst) # (1, 2, 3)
# Tuple to list
new_list = list(tpl) # [4, 5, 6]
# Temporary modification
modified = list(tpl)
modified.append(7)
new_tpl = tuple(modified) # (4, 5, 6, 7)
# Simple conversion timing (machine-dependent)
setup = "data = list(range(100000))"
print("Conversion time (list -> tuple):", timeit("tuple(data)", setup=setup, number=10))
Advanced Hybrid Patterns
Combining tuples and lists effectively:
- **Immutable Core**: Tuples for base data structure
- **Mutable Wrapper**: Lists for modification interface
- **Caching**: Tuples as cache keys for list-based data
- **API Design**: Accept tuples but return lists for flexibility
# Hybrid example
class DataSeries:
def __init__(self, data):
self._data = tuple(data)
def values(self):
return list(self._data) # Safe mutable copy
def normalized(self):
total = sum(self._data) or 1 # Avoid division by zero
return tuple(x/total for x in self._data) # New immutable
series = DataSeries([1, 2, 3])
print("Values:", series.values())
print("Normalized:", series.normalized())
Values: [1, 2, 3] Normalized: (0.166..., 0.333..., 0.5)