05-05: Slicing — Extracting Subsequences¶
Slicing extracts a portion of a sequence (string, list, tuple, range, bytes). The syntax is seq[start:stop:step].
Basic Syntax¶
seq[start:stop] # items from start to stop-1
seq[start:stop:step] # items from start, step apart, up to stop-1
start— index to begin (inclusive), default0stop— index to end (exclusive), defaultlen(seq)step— how many positions to advance, default1
All three are optional. Missing values use their defaults.
String Slicing¶
s = "Hello, Python!"
# 0123456789...
print(s[0:5]) # 'Hello'
print(s[7:13]) # 'Python'
print(s[:5]) # 'Hello' (start defaults to 0)
print(s[7:]) # 'Python!' (stop defaults to end)
print(s[:]) # 'Hello, Python!' (full copy)
print(s[-7:-1]) # 'Python'
print(s[-1]) # '!' (negative index = from end)
List Slicing¶
nums = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
print(nums[2:6]) # [2, 3, 4, 5]
print(nums[:4]) # [0, 1, 2, 3]
print(nums[6:]) # [6, 7, 8, 9]
# Slice returns a new list — original unchanged
sub = nums[2:5]
print(sub) # [2, 3, 4]
print(nums) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# Modifying via slice
nums[2:5] = [20, 30, 40]
print(nums) # [0, 1, 20, 30, 40, 5, 6, 7, 8, 9]
The step Parameter¶
s = "abcdefghij"
print(s[::2]) # 'acegi' — every 2nd character
print(s[1::2]) # 'bdfhj' — every 2nd, start at 1
print(s[::3]) # 'adgj' — every 3rd
# Negative step — go backwards
print(s[::-1]) # 'jihgfedcba' — reversed
print(s[8:2:-1]) # 'ihgfed' — from index 8 down to 3
print(s[::-2]) # 'jhfdb' — every 2nd, reversed
Negative Indices in Slices¶
Negative indices count from the end of the sequence:
s = "Python"
# P y t h o n
# 0 1 2 3 4 5
# -6 -5 -4 -3 -2 -1
print(s[-3:]) # 'hon' — last 3 chars
print(s[:-3]) # 'Pyt' — all except last 3
print(s[-4:-1]) # 'tho' — from -4 to -2
Common Slicing Patterns¶
s = "Hello, World!"
# First n characters
print(s[:5]) # 'Hello'
# Last n characters
print(s[-6:]) # 'World!'
# All except first n
print(s[3:]) # 'lo, World!'
# All except last n
print(s[:-1]) # 'Hello, World'
# Reverse
print(s[::-1]) # '!dlroW ,olleH'
# Every other character
print(s[::2]) # 'Hlo ol!'
# Middle part
n = len(s)
print(s[n//4: 3*n//4]) # middle half
# Capitalize first character
print(s[0].upper() + s[1:])
Slicing Lists¶
lst = [10, 20, 30, 40, 50, 60, 70]
# First half
half = len(lst) // 2
print(lst[:half]) # [10, 20, 30]
print(lst[half:]) # [40, 50, 60, 70]
# Rotate left by k
def rotate_left(lst, k):
k = k % len(lst)
return lst[k:] + lst[:k]
print(rotate_left([1,2,3,4,5], 2)) # [3, 4, 5, 1, 2]
# Rotate right by k
def rotate_right(lst, k):
k = k % len(lst)
return lst[-k:] + lst[:-k]
print(rotate_right([1,2,3,4,5], 2)) # [4, 5, 1, 2, 3]
# Reverse
print(lst[::-1]) # [70, 60, 50, 40, 30, 20, 10]
Slice Assignment¶
Lists support assigning to a slice — this can change the list's size:
lst = [1, 2, 3, 4, 5]
# Replace a slice
lst[1:3] = [20, 30]
print(lst) # [1, 20, 30, 4, 5]
# Replace with different length (list grows)
lst[1:3] = [10, 11, 12, 13]
print(lst) # [1, 10, 11, 12, 13, 4, 5]
# Delete a slice (replace with empty)
lst[1:4] = []
print(lst) # [1, 13, 4, 5]
# Insert at position (replace empty slice)
lst[2:2] = [99, 98]
print(lst) # [1, 13, 99, 98, 4, 5]
Slicing Tuples¶
Tuples support slicing but not slice assignment (immutable):
t = (1, 2, 3, 4, 5)
print(t[1:4]) # (2, 3, 4)
print(t[::-1]) # (5, 4, 3, 2, 1)
print(t[::2]) # (1, 3, 5)
# Reassemble with slicing
first, *middle, last = t
print(first, middle, last) # 1 [2, 3, 4] 5
Slicing range()¶
r = range(10)
print(r[2:7]) # range(2, 7)
print(list(r[2:7])) # [2, 3, 4, 5, 6]
print(list(r[::3])) # [0, 3, 6, 9]
The slice Object¶
A reusable slice object can be created:
data = [10, 20, 30, 40, 50, 60, 70, 80, 90]
# Create named slices
first_half = slice(None, len(data)//2)
last_half = slice(len(data)//2, None)
every_odd = slice(None, None, 2)
print(data[first_half]) # [10, 20, 30, 40]
print(data[last_half]) # [50, 60, 70, 80, 90]
print(data[every_odd]) # [10, 30, 50, 70, 90]
# Useful for spreadsheet-like column access
PRICE = slice(0, 8)
VOLUME = slice(8, 16)
row = "1234.569987654"
print(row[PRICE]) # '1234.569'
print(row[VOLUME]) # '987654'
Practical Examples¶
Extracting parts of a string¶
# Email parsing
email = "alice.smith@example.com"
at_pos = email.index("@")
dot_pos = email.rindex(".")
username = email[:at_pos] # 'alice.smith'
domain = email[at_pos+1:] # 'example.com'
tld = email[dot_pos+1:] # 'com'
# Phone formatting
phone = "1234567890"
formatted = f"({phone[:3]}) {phone[3:6]}-{phone[6:]}"
print(formatted) # (123) 456-7890
# Credit card masking
card = "4111111111111234"
masked = "*" * 12 + card[-4:]
print(masked) # ************1234
Checking palindromes¶
def is_palindrome(s):
s = s.lower().replace(" ", "")
return s == s[::-1]
print(is_palindrome("racecar")) # True
print(is_palindrome("A man a plan a canal Panama")) # True
print(is_palindrome("hello")) # False
Chunking a list¶
def chunk(lst, n):
"""Split list into chunks of size n"""
return [lst[i:i+n] for i in range(0, len(lst), n)]
print(chunk([1,2,3,4,5,6,7,8,9], 3))
# [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
Quick Reference¶
| Pattern | Result |
|---|---|
s[a:b] |
chars/items from a to b-1 |
s[:b] |
first b items |
s[a:] |
from a to end |
s[:] |
copy of entire sequence |
s[-n:] |
last n items |
s[:-n] |
all except last n |
s[::k] |
every k-th item |
s[::-1] |
reversed |
s[a:b:k] |
from a to b-1, step k |
Exercises: 05-05: Exercises — Slicing
⬅️ Previous: 05-04: Dictionaries ➡️ Next: 05-06: Data Structures Comparison — str, list, tuple, set, dict