Python tutorials > Core Python Fundamentals > Control Flow > How to iterate over sequences?

How to iterate over sequences?

Iterating Over Sequences in Python

Python provides several ways to iterate over sequences like lists, tuples, and strings. Understanding these methods is fundamental to effective Python programming.

Basic Iteration with a `for` Loop

The most common way to iterate is using a `for` loop. This loop iterates through each element in the sequence, assigning it to the loop variable (here, `item`) for each iteration. In this example, each number in `my_list` is printed to the console.

my_list = [1, 2, 3, 4, 5]

for item in my_list:
    print(item)

Iteration with `range()`

The `range()` function generates a sequence of numbers. Combined with `len()`, it allows iteration using indices. `range(len(my_list))` creates a sequence of numbers from 0 up to (but not including) the length of the list. This is useful when you need to access elements based on their position.

my_list = [10, 20, 30, 40, 50]

for i in range(len(my_list)):
    print(f"Index: {i}, Value: {my_list[i]}")

Iteration with `enumerate()`

The `enumerate()` function provides both the index and the value of each element in the sequence. This is a more Pythonic and often more readable alternative to using `range(len(my_list))` when you need both the index and the value.

my_list = ['apple', 'banana', 'cherry']

for index, fruit in enumerate(my_list):
    print(f"Index: {index}, Fruit: {fruit}")

Iterating over Strings

Strings are also sequences and can be iterated over in the same way as lists or tuples. Each character in the string is processed in each iteration of the loop.

my_string = "Python"

for char in my_string:
    print(char)

Iteration with `while` Loop

The `while` loop allows iteration as long as a certain condition is met. In this example, the loop continues as long as the `index` is less than the length of the list. `while` loops require manual incrementing of the index.

my_list = [1, 2, 3, 4, 5]
index = 0

while index < len(my_list):
    print(my_list[index])
    index += 1

Concepts Behind the Snippet

The fundamental concepts involve the understanding of sequences (ordered collections of items), loops (repeating a block of code), indices (the position of an item within a sequence), and iterators (objects that allow traversal through a sequence).

Real-Life Use Case

Imagine processing a list of user emails. You could iterate over the list to send personalized messages to each user, or perhaps check if each user has confirmed their email address and update the status accordingly. Another use case is processing data read from a file, where each line represents a data record.

Example:

email_list = ["user1@example.com", "user2@example.com", "user3@example.com"] for email in email_list: send_email(email, "Subject: Important Update", "Body: Please read this...")

Best Practices

  • Use enumerate() whenever you need both the index and the value.
  • Prefer for loops over while loops for simple iteration unless you need a more complex exit condition.
  • Avoid modifying the sequence while iterating over it (e.g., adding or removing elements), as this can lead to unexpected behavior. If modification is necessary, consider creating a copy of the sequence first.
  • Use descriptive variable names for readability.

Interview Tip

Be prepared to discuss the differences between `for` and `while` loops and explain when you would choose one over the other. Also, understand the nuances of using `range()` and `enumerate()`. Be able to explain how to handle edge cases, such as empty sequences. The interviewer may also ask you to solve problems that involve iterating through sequences and manipulating the data.

When to Use Them

  • `for` loop: Use when you know the sequence you need to iterate over. It is ideal when you need to perform an action for each item in the sequence.
  • `while` loop: Use when you need to repeat a block of code until a certain condition is met, which is not necessarily tied to a sequence. For instance, waiting for user input or processing data until a specific value is reached.
  • `enumerate()`: Use when you need both the index and value of each element during iteration.
  • `range()`: Use when you specifically need to iterate based on indices.

Memory Footprint

Iterating directly over a sequence (e.g., `for item in my_list`) generally has a lower memory footprint than using `range(len(my_list))` because you are accessing the elements directly. `range()` creates a list of indices in memory, which can be significant for large lists. `enumerate()` also has a relatively low overhead. Using generators (with the 'yield' keyword) for larger datasets can significantly reduce memory usage by only creating one element at a time during iteration.

Alternatives

  • List Comprehensions: Provide a concise way to create new lists based on existing sequences. new_list = [x2 for x in my_list]
  • Generators: Similar to list comprehensions but create an iterator instead of a list, saving memory. my_generator = (x2 for x in my_list)
  • Map Function: Applies a function to each item in a sequence. new_list = list(map(lambda x: x2, my_list))
  • Filter Function: Creates a new sequence containing only the elements that satisfy a given condition. new_list = list(filter(lambda x: x > 5, my_list))

Pros of `for` loops with direct iteration (e.g., `for item in my_list`)

  • Readability: Often easier to read and understand.
  • Efficiency: Generally more efficient as it directly accesses elements.
  • Pythonic: Considered the more Pythonic way to iterate.

Cons of `for` loops with direct iteration

  • No direct access to index: Requires using enumerate() if the index is needed.

Pros of `for` loops with `range(len(my_list))`

  • Direct access to index: Allows easy access to the index of each element.

Cons of `for` loops with `range(len(my_list))`

  • Less Readable: Can be less readable than direct iteration.
  • Potentially less efficient: Can be less efficient, especially for large lists.

FAQ

  • What happens if I modify a list while iterating over it?

    Modifying a list while iterating over it can lead to unexpected behavior. Elements might be skipped or processed multiple times. It's generally best to avoid modifying the list in place. If you need to modify it, create a copy and iterate over the copy instead or build a new list with the desired changes.
  • How can I iterate over multiple sequences simultaneously?

    You can use the zip() function to iterate over multiple sequences in parallel. It combines elements from each sequence into tuples. for item1, item2 in zip(list1, list2): print(item1, item2)
  • Can I iterate over dictionaries?

    Yes, you can iterate over dictionaries. By default, you iterate over the keys: for key in my_dict: print(key). You can also iterate over the values: for value in my_dict.values(): print(value). To iterate over both keys and values, use: for key, value in my_dict.items(): print(key, value)