tuple Optimization¶
Tuples are optimized in CPython through tuple interning and caching, making them faster for hashable collections and reducing memory usage. Understanding these optimizations explains why tuples are preferred for immutable sequences and dictionary keys.
Mental Model
Because tuples are immutable, CPython can cache and reuse them aggressively. Small tuples with constant elements may be interned (shared across your program), and freed tuples are recycled from a free list instead of being garbage-collected. This makes tuple creation and destruction significantly cheaper than list equivalents.
Tuple Interning¶
Small Tuple Caching¶
```python a = (1, 2, 3) b = (1, 2, 3) print(f"Same object: {a is b}")
c = tuple([1, 2, 3]) print(f"Constructed tuple same: {a is c}") ```
Output:
Same object: True
Constructed tuple same: False
String Tuple Interning¶
python
t1 = ("hello", "world")
t2 = ("hello", "world")
print(f"String tuples same: {t1 is t2}")
Output:
String tuples same: True
Memory Efficiency¶
Tuple vs List Comparison¶
```python import sys
t = (1, 2, 3, 4, 5) l = [1, 2, 3, 4, 5]
print(f"Tuple size: {sys.getsizeof(t)} bytes") print(f"List size: {sys.getsizeof(l)} bytes") ```
Output:
Tuple size: 56 bytes
List size: 64 bytes
Tuple Unpacking Optimization¶
Fast Unpacking¶
```python def swap(a, b): return b, a
x = 1 y = 2 x, y = swap(x, y) print(f"Swapped: x={x}, y={y}") ```
Output:
Swapped: x=2, y=1
Practical Advantages¶
Hashable for Dictionaries¶
```python
Tuples can be dict keys¶
coordinates = { (0, 0): "origin", (1, 0): "right", (0, 1): "up" }
print(coordinates[(1, 0)]) ```
Output:
right
Function Return Optimization¶
```python def get_coordinates(): return 10, 20
x, y = get_coordinates() print(f"Coordinates: ({x}, {y})") ```
Output:
Coordinates: (10, 20)
Exercises¶
Exercise 1.
Compare the memory usage of a tuple and a list containing the same 1000 integers using sys.getsizeof(). Which uses less memory and why?
Solution to Exercise 1
```python
import sys
data = list(range(1000))
t = tuple(data)
l = list(data)
print(f"Tuple: {sys.getsizeof(t)} bytes")
print(f"List: {sys.getsizeof(l)} bytes")
```
Tuples use less memory because they are fixed-size and do not need to store extra capacity for potential growth. Lists allocate extra space to support efficient appending.
Exercise 2. Demonstrate that tuples are hashable (and can be used as dictionary keys) while lists are not. Create a dictionary that maps (x, y) coordinate tuples to city names.
Solution to Exercise 2
```python
cities = {
(37.5665, 126.9780): "Seoul",
(35.6762, 139.6503): "Tokyo",
(40.7128, -74.0060): "New York",
}
print(cities[(37.5665, 126.9780)]) # Seoul
try:
bad = {[37.5665, 126.9780]: "Seoul"}
except TypeError as e:
print(f"Error: {e}") # unhashable type: 'list'
```
Tuples are immutable and hashable, making them valid dictionary keys. Lists are mutable and unhashable.
Exercise 3. Explain what tuple packing and unpacking are. Write an example that uses both in a function that returns multiple values.
Solution to Exercise 3
```python
# Tuple packing: multiple values packed into a tuple
coordinates = 37.5665, 126.9780 # packing
print(type(coordinates)) # <class 'tuple'>
# Tuple unpacking: extracting values from a tuple
lat, lon = coordinates # unpacking
print(f"Latitude: {lat}, Longitude: {lon}")
# Common pattern: function returning multiple values
def min_max(numbers):
return min(numbers), max(numbers) # packing
lo, hi = min_max([3, 1, 4, 1, 5, 9]) # unpacking
print(f"Min: {lo}, Max: {hi}") # Min: 1, Max: 9
```
Packing creates a tuple from comma-separated values. Unpacking assigns tuple elements to individual variables.