Chapter 6

Sequences

6.1 Lists · 6.2 Aliasing and Copying · 6.3 Tuples

← → or Space to navigate · F for fullscreen

6.1 Lists

Ordered, mutable sequences — Python's most versatile collection

Creating and Accessing Lists

Literal

fruits = ["apple", "banana", "cherry"]
mixed  = [1, "hello", 3.14, True]
empty  = []

list() constructor

list("abc")        # ['a', 'b', 'c']
list(range(5))     # [0, 1, 2, 3, 4]
list((1, 2, 3))    # from tuple

List comprehension

squares = [x**2 for x in range(6)]
# [0, 1, 4, 9, 16, 25]

evens = [x for x in range(10) if x % 2 == 0]

Nested lists

matrix = [[1, 2], [3, 4], [5, 6]]
matrix[1][0]   # 3

Strings ↔ Lists

words = "hello world".split()
# ['hello', 'world']

" ".join(words)   # 'hello world'

Lists are mutable — elements can be added, removed, or changed after creation. Order is preserved and duplicates are allowed.

Accessing & Slicing

Indexing (zero-based)

fruits = ["apple", "banana", "cherry"]

fruits[0]    # 'apple'
fruits[-1]   # 'cherry'   (last element)
fruits[10]   # IndexError

Slicing [start:stop:step]

fruits[1:]    # ['banana', 'cherry']
fruits[:2]    # ['apple', 'banana']
fruits[::2]   # every other element
fruits[::-1]  # reversed

Query methods

nums = [3, 1, 4, 1, 5, 9, 2, 6]

len(nums)         # 8
nums.count(1)     # 2
nums.index(5)     # 4  (first occurrence)
5 in nums         # True

Unpacking

a, b, c = [10, 20, 30]
first, *rest = [1, 2, 3, 4]
# first=1, rest=[2, 3, 4]

Updating and Transforming Lists

Add elements

fruits.append("date")          # end
fruits.insert(1, "avocado")    # at index
fruits.extend(["elderberry"])  # merge list

Remove elements

fruits.remove("banana")   # by value
fruits.pop()              # last (returns it)
fruits.pop(0)             # by index
del fruits[1]             # by index, no return
fruits.clear()            # empty the list

Sort & reverse

nums = [3, 1, 4, 1, 5]
nums.sort()              # in-place
nums.sort(reverse=True)
nums.reverse()           # in-place

sorted(nums)             # returns new list

Useful helpers

min(nums), max(nums), sum(nums)
enumerate(nums)   # (index, value) pairs
zip(a, b)         # pair two lists

6.2 Aliasing and Copying

Names, references, and independent copies

Aliasing vs. Copying

Aliasing — shared reference

a = [1, 2, 3]
b = a          # b points to same list
b.append(4)
print(a)       # [1, 2, 3, 4]  ← changed!

Shallow copy — independent top level

b = a[:]       # slice copy
b = a.copy()   # .copy() method
b = list(a)    # list() constructor

b.append(4)
print(a)       # [1, 2, 3]  ← safe

Deep copy — independent at every level

import copy

nested = [[1, 2], [3, 4]]
deep = copy.deepcopy(nested)

deep[0].append(99)
print(nested)  # [[1, 2], [3, 4]]  ← safe

Shallow copy is safe for flat lists. Use deepcopy when the list contains other mutable objects (nested lists, dicts).

6.3 Tuples

Ordered, immutable sequences: fixed records that are safe to share

Creating and Accessing Tuples

Literal (comma makes the tuple)

point   = (3, 4)
single  = (42,)     # trailing comma required
empty   = ()
no_paren = 1, 2, 3  # parens optional

tuple() constructor

tuple([1, 2, 3])    # from list
tuple("abc")        # ('a', 'b', 'c')
tuple(range(4))     # (0, 1, 2, 3)

Accessing (same as lists)

point[0]     # 3
point[-1]    # 4
point[0:1]   # (3,)

Use a tuple when data should not change: coordinates, dates, rows of a report, function return values.

Choosing list vs. tuple

list tuple
Mutable ✓ ✗
Methods many count, index
Use case collections that change fixed records

Immutability

Tuples cannot change

point = (3, 4, 5)
point[0] = 99            # TypeError

new_point = point[:2] + (0,)   # build a new tuple

Tuples that contain lists

record = ('Ana', [91, 84])
record[1].append(77)     # OK: the list changes
record[1] = [100]        # TypeError: can't replace

Safe to share

def add_bonus(scores):
    scores[0] = scores[0] + 5

add_bonus([80, 90])      # changes the caller's list
add_bonus((80, 90))      # TypeError: tuple is safe

def with_bonus(scores):  # return a new tuple instead
    return tuple([s + 5 for s in scores])

A tuple's items cannot be replaced, but a list inside a tuple can still change. For a fully fixed record, store only immutable values.

Unpacking and Function Design

Basic unpacking

x, y = (3, 4)
a, b, c = "abc"       # works on any iterable

# starred unpacking
first, *rest = (1, 2, 3, 4)
# first=1, rest=[2, 3, 4]

zip() and enumerate()

names  = ["alice", "bob"]
scores = [92, 85]

for name, score in zip(names, scores):
    print(name, score)

for i, name in enumerate(names):
    print(i, name)

Multiple return values

def min_max(nums):
    return min(nums), max(nums)  # returns tuple

lo, hi = min_max([3, 1, 4, 1, 5])

Argument packing with *args

def total(*args):    # args is a tuple
    return sum(args)

total(1, 2, 3, 4)   # 10

Sorting with a key function

pairs = [("bob", 85), ("alice", 92)]

def second_element(t):
    return t[1]

sorted(pairs, key=second_element)  # by score

Tuples as Records

Lists of tuples

lines = ['North,Jan,112', 'South,Jan,98']

sales = []
for line in lines:
    region, month, amount = line.split(',')
    sales.append((region, month, int(amount)))

for region, month, amount in sales:
    print(region, month, amount)

Named tuples

from collections import namedtuple

Sale = namedtuple('Sale', ['region', 'month', 'amount'])
s = Sale('North', 'Jan', 112)

s.amount    # 112, by name
s[2]        # 112, by position

pandas' DataFrame.itertuples() returns each row as a named tuple.

Chapter 6 — Quick Reference

Type Ordered Mutable Duplicates Literal
list ✓ ✓ ✓ [1, 2]
tuple ✓ ✗ ✓ (1, 2)
Task Idiom
Unpack a, b, *rest = lst
Copy flat list lst[:] or lst.copy()
Multiple return return a, b → unpack with x, y = f()
Named record Sale = namedtuple('Sale', ['region', 'amount'])
Membership x in lst — checks each item in turn, O(n)

End of Chapter 6

Next: Chapter 7 — Dictionaries

key-value mappings · core operations · dictionary patterns · sets