DEV Community

Cover image for The Immutable Exhibition: Why Tuples Never Change
Aaron Rose
Aaron Rose

Posted on

The Immutable Exhibition: Why Tuples Never Change

Timothy had mastered lists for organizing books, but one afternoon Margaret led him to a restricted section of the library: The Locked Display Cases. Here, collections were sealed behind glass—visible but permanently unchangeable.


The Permanent Collections

"These are tuples," Margaret explained, gesturing to the display cases. "They look similar to lists but with one crucial difference: once created, they can never be modified."

Timothy examined a case containing coordinate pairs for mapping the library:

main_entrance = (42, 15)  # x, y coordinates
rare_books_section = (108, 73)

# Can read the values
x_position = main_entrance[0]  # 42
y_position = main_entrance[1]  # 15

# Cannot modify them
main_entrance[0] = 50  # TypeError: tuple doesn't support item assignment
Enter fullscreen mode Exit fullscreen mode

The parentheses instead of square brackets signaled this permanent nature. Once the coordinates were set, they remained fixed forever.

The Similarity Paradox

Timothy noticed tuples behaved like lists in many ways:

book_info = ("1984", "Orwell", 1949, "Dystopian")

# Indexing works
title = book_info[0]  # "1984"
author = book_info[1]  # "Orwell"

# Slicing works
metadata = book_info[2:]  # (1949, "Dystopian")

# Iteration works
for item in book_info:
    print(item)

# Length works
num_fields = len(book_info)  # 4
Enter fullscreen mode Exit fullscreen mode

But any attempt to change the tuple failed:

book_info[0] = "Animal Farm"  # TypeError
book_info.append("Fiction")   # AttributeError: no append method
del book_info[1]               # TypeError: doesn't support deletion
Enter fullscreen mode Exit fullscreen mode

Margaret explained: "Tuples are read-only sequences. They provide all the access operations of lists but none of the modification operations."

The Dictionary Key Capability

Timothy recalled his earlier lesson about dictionary keys requiring immutability. Margaret showed him tuples' power as compound keys:

library_map = {}

# Tuples work perfectly as dictionary keys
library_map[(1, 1)] = "Entrance Hall"
library_map[(1, 2)] = "Reference Desk"
library_map[(2, 1)] = "Fiction Section"

# Retrieve by coordinate
location = library_map[(1, 2)]  # "Reference Desk"

# Lists cannot do this
library_map[[1, 3]] = "Poetry"  # TypeError: unhashable type: list
Enter fullscreen mode Exit fullscreen mode

The tuple's immutability made it hashable—meaning it had a hash value that would never change—and suitable as a dictionary key. Lists could never achieve this because their contents could change, which would change their hash value and break the dictionary's filing system.

The Fixed Record Pattern

Margaret showed Timothy how tuples naturally represented fixed records—data that belonged together and shouldn't change:

# Database query returns tuples
def get_book_record(book_id):
    return ("The Great Gatsby", "F. Scott Fitzgerald", 1925)

book = get_book_record(42)
title, author, year = book

# Color RGB values - these should never change
RED = (255, 0, 0)
BLUE = (0, 0, 255)

# Geographic coordinates - permanent locations
LIBRARY_LOCATION = (40.7128, -74.0060)  # latitude, longitude
Enter fullscreen mode Exit fullscreen mode

Each tuple represented a logical unit of related but unchanging data. The immutability signaled to other programmers: "This data is meant to stay together and stay constant."

The Performance Advantage

Timothy asked whether tuples' restrictions made them slower. Margaret surprised him: "Actually, tuples are slightly faster and more memory-efficient than lists precisely because they can't change."

import sys

small_list = [1, 2, 3]
small_tuple = (1, 2, 3)

list_size = sys.getsizeof(small_list)    # 88 bytes
tuple_size = sys.getsizeof(small_tuple)  # 72 bytes
Enter fullscreen mode Exit fullscreen mode

Because tuples couldn't grow or shrink, Python allocated exactly the memory needed without overhead for future modifications. Tuple creation was also faster since Python didn't need to account for potential changes.

The Single Element Trap

Timothy discovered a peculiar syntax requirement when creating single-element tuples:

not_a_tuple = (42)      # This is just an integer in parentheses
actual_tuple = (42,)    # Trailing comma makes it a tuple

print(type(not_a_tuple))   # <class 'int'>
print(type(actual_tuple))  # <class 'tuple'>
Enter fullscreen mode Exit fullscreen mode

Margaret explained: "The comma creates the tuple, not the parentheses. Parentheses are often optional, but the comma is essential."

# These are all valid tuples
coordinates = 10, 20           # (10, 20)
rgb_color = 255, 0, 0         # (255, 0, 0)
single_item = "alone",        # ("alone",)
Enter fullscreen mode Exit fullscreen mode

The Mutability Within Immutability

Timothy encountered a confusing case: a tuple containing a list.

mixed_collection = ("Fixed", "Data", [1, 2, 3])

# Cannot replace the list
mixed_collection[2] = [4, 5, 6]  # TypeError

# But can modify the list itself!
mixed_collection[2].append(4)    # This works!
print(mixed_collection)          # ("Fixed", "Data", [1, 2, 3, 4])
Enter fullscreen mode Exit fullscreen mode

Margaret clarified: "The tuple is immutable—you can't change which objects it contains. But if one of those objects is mutable, you can still modify that object. The tuple holds references, and those references never change, even if the objects they point to do change."

This subtlety meant tuples only guaranteed immutability of the container structure, not necessarily of the contained data.

The Practical Applications

Timothy discovered tuples solved several common patterns:

Returning multiple values from functions:

def get_book_stats(book_id):
    title = "1984"
    checkouts = 42
    rating = 4.5
    return title, checkouts, rating  # Returns a tuple

book_title, times_borrowed, avg_rating = get_book_stats(101)
Enter fullscreen mode Exit fullscreen mode

Protecting data from accidental modification:

# Constants use ALL_CAPS naming convention to signal permanence
WEEKDAYS = ("Monday", "Tuesday", "Wednesday", "Thursday", "Friday")
MAX_CONNECTIONS = (100, 200, 500)  # Tier limits
# Impossible to accidentally modify these constants
Enter fullscreen mode Exit fullscreen mode

Efficient data exchange:

def swap_values(a, b):
    return b, a  # Tuple packing and unpacking

x, y = 10, 20
x, y = swap_values(x, y)  # x is now 20, y is now 10
Enter fullscreen mode Exit fullscreen mode

Timothy's Tuple Wisdom

Through exploring the Locked Display Cases, Timothy learned key principles:

Tuples signal intent: When you use a tuple, you're telling other programmers this data shouldn't change.

Immutability enables hashability: Tuples can be dictionary keys and set members; lists cannot.

Performance matters: Tuples are lighter and faster than lists for fixed collections.

Structure over modification: Use tuples for records, coordinates, and fixed sequences; use lists when you need to add, remove, or change items.

The comma creates the tuple: Remember the trailing comma for single-element tuples.

Timothy's exploration of tuples revealed that not every collection needed the flexibility of lists. Sometimes the best tool was the one that couldn't be changed—a permanent exhibition that guaranteed stability and enabled capabilities impossible with mutable collections.


Aaron Rose is a software engineer and technology writer at tech-reader.blog and the author of Think Like a Genius.

Top comments (0)