Collections
Tuples
Immutable Sequences
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.
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.
Represent RGB colors
Store color components as a fixed triplet.
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.
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.
Return multiple values
Functions can return tuples for multiple return values.
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.
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].
Exercise: tuple_vs_list.py
Explore when to choose tuple vs list