You're storing a point (x, y) that shouldn't change. A list could be accidentally modified. A tuple is immutable - once created, it's fixed. Perfect for coordinates, RGB colors, and returning multiple values from functions.

Store coordinates

Create a tuple for a point in 2D space.

coordinates.py
def main():
    # Coordinates as tuples (x, y)
    origin = (0, 0)
    home = (10, 25)
    office = (50, 30)
    store = (35, 15)
    
    print("=== Location Coordinates ===")
    print(f"Home: {home}")
    print(f"Office: {office}")
    print(f"Store: {store}")
    
    # Access individual values
    home_x = home[0]
    home_y = home[1]
    print(f"\nHome is at x={home_x}, y={home_y}")
    
    # 3D coordinates
    point_3d = (10, 20, 30)
    print(f"\n3D Point: {point_3d}")
    x, y, z = point_3d
    print(f"x={x}, y={y}, z={z}")
    
    # Calculate distance from origin
    import math
    def distance_from_origin(point):
        return math.sqrt(point[0]**2 + point[1]**2)
    
    print("\n=== Distance from Origin ===")
    locations = [("Home", home), ("Office", office), ("Store", store)]
    for name, coord in locations:
        dist = distance_from_origin(coord)
        print(f"{name}: {dist:.2f} units")

main()

Tuples use parentheses: (x, y). Access by index like lists.

tuple Immutable sequence: `(1, 2, 3)`. Cannot be modified after creation.

Represent RGB colors

Store color components as a fixed triplet.

rgb_color.py
def main():
    # RGB colors as tuples (red, green, blue)
    # Each value: 0-255
    red = (255, 0, 0)
    green = (0, 255, 0)
    blue = (0, 0, 255)
    white = (255, 255, 255)
    black = (0, 0, 0)
    orange = (255, 165, 0)
    
    print("=== RGB Color Palette ===")
    colors = {
        "Red": red,
        "Green": green,
        "Blue": blue,
        "White": white,
        "Black": black,
        "Orange": orange
    }
    
    for name, rgb in colors.items():
        print(f"{name}: RGB{rgb}")
    
    # Color mixing (additive)
    print("\n=== Color Analysis ===")
    target_color = orange
    r, g, b = target_color
    
    print(f"Orange = RGB{target_color}")
    print(f"  Red component:   {r}")
    print(f"  Green component: {g}")
    print(f"  Blue component:  {b}")
    
    # Brightness (simple average)
    brightness = (r + g + b) / 3
    print(f"  Brightness: {brightness:.1f}/255")
    
    # RGBA with alpha channel
    transparent_red = (255, 0, 0, 128)
    r, g, b, a = transparent_red
    print(f"\nRGBA with alpha: {transparent_red}")
    print(f"  Opacity: {a/255*100:.0f}%")

main()

(red, green, blue) with values 0-255. Immutability prevents accidental changes.

Unpack tuple values

Assign tuple elements to individual variables.

unpacking.py
def main():
    # Basic tuple unpacking
    coordinates = (100, 250)
    x, y = coordinates
    
    print("=== Basic Unpacking ===")
    print(f"Tuple: {coordinates}")
    print(f"x = {x}, y = {y}")
    
    # Unpacking in loop
    print("\n=== Unpacking in Loops ===")
    points = [(0, 0), (10, 20), (30, 40), (50, 60)]
    
    for x, y in points:
        distance = (x**2 + y**2) ** 0.5
        print(f"Point ({x}, {y}) is {distance:.2f} from origin")
    
    # Swap variables using unpacking
    print("\n=== Variable Swap ===")
    a, b = 5, 10
    print(f"Before: a={a}, b={b}")
    a, b = b, a
    print(f"After:  a={a}, b={b}")
    
    # Extended unpacking with * (Python 3+)
    numbers = (1, 2, 3, 4, 5, 6, 7)
    first, *middle, last = numbers
    print("\n=== Extended Unpacking ===")
    print(f"Numbers: {numbers}")
    print(f"First: {first}")
    print(f"Middle: {middle}")
    print(f"Last: {last}")
    
    # Ignore values with _
    print("\n=== Ignoring Values ===")
    data = ("John", "Doe", 30, "Engineer", "NYC")
    first_name, last_name, _, job, _ = data
    print(f"{first_name} {last_name} works as {job}")

main()

x, y = point extracts values. Number of variables must match tuple length.

unpacking Extract values: `a, b, c = tuple`. Also works with `*rest` for variable length.

Return multiple values

Functions can return tuples for multiple return values.

return_multiple.py
def main():
    # Functions can return multiple values via tuple
    
    def get_min_max(numbers):
        """Return both minimum and maximum in one call."""
        return min(numbers), max(numbers)  # Returns a tuple!
    
    scores = [85, 92, 78, 95, 88, 73, 91]
    
    print("=== Student Scores ===")
    print(f"Scores: {scores}")
    
    # Receive both values
    lowest, highest = get_min_max(scores)
    print(f"Lowest: {lowest}")
    print(f"Highest: {highest}")
    
    # Extended version with more statistics
    def get_stats(numbers):
        """Return comprehensive statistics."""
        total = sum(numbers)
        count = len(numbers)
        average = total / count
        minimum = min(numbers)
        maximum = max(numbers)
        return minimum, maximum, average, total, count
    
    low, high, avg, total, n = get_stats(scores)
    print(f"\n=== Detailed Statistics ===")
    print(f"Count: {n}")
    print(f"Sum: {total}")
    print(f"Average: {avg:.2f}")
    print(f"Range: {low} to {high}")
    
    # Divmod - built-in that returns tuple
    print("\n=== Built-in divmod() ===")
    total_minutes = 137
    hours, minutes = divmod(total_minutes, 60)
    print(f"{total_minutes} minutes = {hours}h {minutes}m")
    
    # Can also keep as tuple
    print("\n=== Keeping as Tuple ===")
    result = get_min_max(scores)  # Don't unpack
    print(f"Result tuple: {result}")
    print(f"Type: {type(result)}")

main()

return x, y implicitly creates a tuple. Caller can unpack or use as tuple.

Named tuples for clarity

Use named tuples for self-documenting fields.

named_tuple.py
from collections import namedtuple

def main():
    # Regular tuple - position-based access
    person_tuple = ("Alice", 30, "Engineer")
    print("=== Regular Tuple ===")
    print(f"Data: {person_tuple}")
    print(f"Name: {person_tuple[0]}")  # What is [0]? Hard to remember!
    print(f"Age: {person_tuple[1]}")
    
    # Named tuple - name-based access!
    Person = namedtuple('Person', ['name', 'age', 'job'])
    
    alice = Person("Alice", 30, "Engineer")
    bob = Person(name="Bob", age=25, job="Designer")
    
    print("\n=== Named Tuple ===")
    print(f"Alice: {alice}")
    print(f"Name: {alice.name}")  # Much clearer!
    print(f"Age: {alice.age}")
    print(f"Job: {alice.job}")
    
    # Still works with index too
    print(f"Index access still works: {alice[0]}")
    
    # Unpacking works
    name, age, job = bob
    print(f"\nUnpacked Bob: {name}, {age}, {job}")
    
    # Named tuple for coordinates
    Point = namedtuple('Point', ['x', 'y'])
    
    print("\n=== Points as Named Tuples ===")
    origin = Point(0, 0)
    destination = Point(100, 50)
    
    dx = destination.x - origin.x
    dy = destination.y - origin.y
    distance = (dx**2 + dy**2) ** 0.5
    
    print(f"From: {origin}")
    print(f"To: {destination}")
    print(f"Distance: {distance:.2f}")
    
    # Create from existing tuple
    data = (200, 300)
    point = Point._make(data)
    print(f"\nCreated from tuple: {point}")
    
    # Convert to dictionary
    print(f"As dict: {point._asdict()}")

main()

namedtuple gives names to positions: point.x instead of point[0].

namedtuple Tuple with named fields: `Point = namedtuple('Point', ['x', 'y'])`.

Exercise: tuple_vs_list.py

Explore when to choose tuple vs list