Sequences and Iterables
Python provides many ways to work with collections of data. Understanding what sequences and iterables are, and how they differ, is crucial for effective Python programming. These concepts form the foundation for working with multiple items at once.
What are Sequences?
A sequence in Python is an ordered collection of items where each item has a specific position (index). The order is deterministic, meaning the same sequence will always have the same order. Sequences are a fundamental data type in Python and are used extensively in loops.
Types of Sequences
Python has seven built-in sequence types:
- Strings (
str) - Ordered collection of characters - Lists (
list) - Ordered, mutable collection of items - Tuples (
tuple) - Ordered, immutable collection of items - Range objects (
range) - Immutable sequence of numbers - Bytes (
bytes) - Immutable sequence of bytes - Bytearrays (
bytearray) - Mutable sequence of bytes - Buffers - Low-level sequence interface
Tip
We’ve already seen strings and will learn more about them along with lists and tuples in later sections. The
range()function we covered earlier is also a sequence type!
Characteristics of Sequences
All sequences share these key characteristics:
- Ordered: Items have a specific position (index starting from 0)
- Indexable: Access items by their position using
[index] - Sliceable: Extract portions using slicing
[start:end] - Length: Get the number of items using
len() - Iterable: Can be processed item by item
What are Iterables?
An iterable is any object that contains or can produce a series of items that can be accessed one at a time. It’s a broader concept than sequences. All sequences are iterables, but not all iterables are sequences.
Key Difference
- Sequences: Have a specific order, are indexable, and have a length
- Iterables: Can produce items one by one, but may not have indexing or a specific order
Examples of Iterables
- Sequences (which are also iterables): strings, lists, tuples, range objects
- Non-sequence iterables: sets, dictionaries, files, generators
The key point is that iterables make it possible to work with collections of items. Sequences are a special type of iterable that provide extra features such as indexing and slicing.
Common Sequence Operations
Sequences support many common operations. Including:
- Membership Testing (
inandnot in) - Length (
len()) - Minimum and Maximum (
min()andmax()) - Counting (
count()) - Searching (
index()) - Indexing (
[i]) - Slicing (
[i:j]and[i:j:k]) - Concatenation (
+) - Repetition (
*)
1. Membership Testing (in and not in)
Check if an item exists in a sequence:
text = "Python"print("P" in text) # Trueprint("x" in text) # Falseprint("x" not in text) # True
numbers = range(1, 6)print(3 in numbers) # Trueprint(10 in numbers) # False2. Length (len())
Get the number of items in a sequence:
text = "Hello"print(len(text)) # 5
numbers = range(1, 6)print(len(numbers)) # 53. Minimum and Maximum (min() and max())
Find the smallest and largest items:
numbers = range(5, 10)print(min(numbers)) # 5print(max(numbers)) # 9
text = "hello"print(min(text)) # 'e' (alphabetically first)print(max(text)) # 'o' (alphabetically last)4. Counting (count())
Count how many times an item appears:
text = "hello"print(text.count("l")) # 2
numbers = range(1, 6)print(numbers.count(2)) # 15. Searching (index())
Find the position of an item (returns the first occurrence):
text = "hello"print(text.index("e")) # 16. Indexing ([i])
Indexing allows access to individual items in a sequence by their position. It’s similar to finding a specific item in a numbered list.
How Indexing Works
Each item in a sequence has a position number called an index. Python uses zero-based indexing, which means:
- The first item is at index 0 (not 1)
- The second item is at index 1
- The third item is at index 2
- And so on…
Here’s a visual example with the string "Python":
Index: 0 1 2 3 4 5String: P y t h o nTo access an item, square brackets [] are used with the index number:
text = "Python"print(text[0]) # 'P' (first character at index 0)print(text[1]) # 'y' (second character at index 1)print(text[2]) # 't' (third character at index 2)print(text[5]) # 'n' (sixth character at index 5)Note
Some programming languages (like Lua) use 1-based indexing, where the first item is at index 1.
Negative Indexing
Negative indexing counts from the end of the sequence:
-1is the last item-2is the second-to-last item-3is the third-to-last item- And so on…
Here’s the same string with negative indices:
Negative Index: -6 -5 -4 -3 -2 -1Index: 0 1 2 3 4 5String: P y t h o nNegative indexing is useful when the length of a sequence is not known but items need to be accessed from the end:
text = "Python"print(text[-1]) # 'n' (last character)print(text[-2]) # 'o' (second-to-last character)print(text[-6]) # 'P' (first character, same as text[0])
numbers = range(10, 41, 10)print(numbers[0]) # 10 (first item)print(numbers[3]) # 40 (last item, at index 3)print(numbers[-1]) # 40 (last item, using negative index)print(numbers[-2]) # 30 (second-to-last item)If an index that doesn’t exist is used (like text[10] for a 6-character string), Python will raise an IndexError. Make sure the index is within the valid range: from 0 to len(sequence) - 1 for positive indices, or from -len(sequence) to -1 for negative indices.
7. Slicing ([i:j] and [i:j:k])
Slicing allows extraction of a portion (or “slice”) of a sequence. Instead of getting one item like indexing, slicing gives a new sequence containing multiple items.
Basic Slicing Syntax
The basic slicing syntax is [start:end]:
start: The index where the slice begins (this item is included)end: The index where the slice ends (this item is excluded)
The end index is exclusive, meaning the item at the end index is NOT included in the slice.
Let’s see this with the string "Python":
Index: 0 1 2 3 4 5String: P y t h o ntext = "Python"
# Get characters from index 0 to 2 (excluding 3)print(text[0:3]) # "Pyt"# Includes: P (index 0), y (index 1), t (index 2)# Excludes: h (index 3)
# Get characters from index 2 to the endprint(text[2:]) # "thon"# When end is omitted, it goes to the end of the sequence# Includes: t, h, o, n (indices 2, 3, 4, 5)
# Get characters from the start to index 3 (excluding 4)print(text[:4]) # "Pyth"# When start is omitted, it starts from the beginning# Includes: P, y, t, h (indices 0, 1, 2, 3)# Excludes: o (index 4)
# Get the entire sequenceprint(text[:]) # "Python"# When both start and end are omitted, you get everythingSlicing with Step
Step can be added to skip items: [start:end:step]
start: Beginning index (inclusive, defaults to 0)end: Ending index (exclusive, defaults to end)step: How many items to skip between each item (defaults to 1)
text = "Python"
# Get every character (step = 1, which is the default)print(text[::1]) # "Python"
# Get every 2nd character (step = 2)print(text[::2]) # "Pto"# Includes: P (index 0), t (index 2), o (index 4)# Skips: y, h, n
# Get characters from index 1 to 5, every 2nd oneprint(text[1:5:2]) # "yh"# Starts at index 1 (y), ends before index 5# Includes: y (index 1), h (index 3)# Skips: t (index 2), o (index 4)Reversing a Sequence
When a negative step (like -1) is used, the sequence can be reversed:
text = "Python"print(text[::-1]) # "nohtyP" (reversed)# The negative step makes it go backwards
print(text[4:2:-1]) # "oh"
# Reverse a portionprint(text[2:5][::-1]) # "oht" (slice first, then reverse)
numbers = range(0, 6)
# Get items from index 1 to 3 (excluding 4)print(numbers[1:4]) # 1, 2, 3
# Get every 2nd itemprint(numbers[::2]) # 0, 2, 4# Includes: 0 (index 0), 2 (index 2), 4 (index 4)
# Get items from index 1 to the end, every 2nd oneprint(numbers[1::2]) # 1, 3, 5
# Reverse the listprint(numbers[::-1]) # 5, 4, 3, 2, 1, 08. Concatenation (+)
Combine two sequences of the same type:
text1 = "Hello"text2 = "World"print(text1 + " " + text2) # "Hello World"9. Repetition (*)
Repeat a sequence multiple times:
text = "Hi"print(text * 3) # "HiHiHi"print(3 * text) # "HiHiHi" (same result)Non-Sequence Types
Not all iterable types are sequences. Some collections don’t maintain order or support indexing. Two important examples are:
- Sets are unordered collections of unique items. They are iterable (you can access each item), but they don’t have a specific order and don’t support indexing:
- Dictionaries store key-value pairs. They maintain insertion order (Python 3.7+), but you access items by key, not by numeric index:
Note
Both sets and dictionaries will be covered in the next chapter.
