# Iterators and Iterables in Python ## What is an Iterable? An **iterable** is any Python object that you can loop over (or iterate through). Some common examples of iterables are lists, tuples, dictionaries, and strings. ### How to identify an Iterable: If an object can return its elements one by one, we call it iterable. It must implement the `__iter__()` method. ### Common Iterable Examples: - **Lists**: `[1, 2, 3]` - **Strings**: `"Hello"` - **Tuples**: `(1, 2, 3)` ### Example of an Iterable: ```python my_list = [1, 2, 3, 4] # This is an iterable for element in my_list: # We can loop through the list using a for loop print(element) ``` Here, `my_list` is an **iterable** # What is an Iterator? An **iterator** is an object that helps you fetch one element at a time from an iterable. To fetch the next element, you use the `next()` function. ## How to identify an Iterator: An iterator object must implement two methods: 1. `__iter__()` – This returns the iterator object itself. 2. `__next__()` – This returns the next value. When there are no more elements, it raises a `StopIteration` exception. ### Example of an Iterator: ```python my_list = [1, 2, 3] # This is an iterable my_iterator = iter(my_list) # Convert the iterable to an iterator using iter() print(next(my_iterator)) # Output: 1 print(next(my_iterator)) # Output: 2 print(next(my_iterator)) # Output: 3 # If we call next() again, it will raise a StopIteration error ``` Here, `my_iterator` is an **iterator**. It gives one value at a time when `next()` is called. Once all values are consumed, calling `next()` again will result in a `StopIteration` error. --- ## Key Differences Between Iterables and Iterators: | **Feature** | **Iterable** | **Iterator** | |------------------|------------------------------------|---------------------------------------------| | **Definition** | An object you can iterate over. | An object that fetches data one element at a time. | | **Methods** | Implements `__iter__()` method. | Implements `__iter__()` and `__next__()` methods. | | **Example** | List, String, Tuple, etc. | Iterator created using `iter()` function. | --- # Making Your Own Iterator You can create a custom iterator by defining a class with `__iter__()` and `__next__()` methods. ## Example: ```python class Counter: def __init__(self, max_value): self.current = 0 self.max_value = max_value def __iter__(self): return self # An iterator must return itself def __next__(self): if self.current < self.max_value: self.current += 1 return self.current else: raise StopIteration # End of iteration counter = Counter(3) # Create an iterator that counts up to 3 for num in counter: print(num) ``` ### Output ``` 1 2 3 ``` ## Built-in Iterables Python has several built-in iterables: - **Lists**: Ordered collections of items (e.g., `[1, 2, 3]`). - **Tuples**: Immutable ordered collections (e.g., `(1, 2, 3)`). - **Sets**: Unordered collections of unique items (e.g., `{1, 2, 3}`). - **Dictionaries**: Collections of key-value pairs (e.g., `{'a': 1, 'b': 2}`). - **Strings**: Sequences of characters (e.g., `"hello"`). - **Ranges**: A sequence of numbers (e.g., `range(5)` produces numbers from 0 to 4). ## Common Exceptions - **StopIteration**: Raised when an iterator's `__next__()` method is called and there are no more items to return. This is a normal way to end iteration. - **TypeError**: Raised if an operation or function is applied to an object of inappropriate type. For example, trying to iterate over an integer will raise this error. ## Iteration with Loops - **For Loop**: You can use a for loop to iterate over an iterable. Python implicitly calls `iter()` on the iterable and uses `next()` to get elements until a `StopIteration` exception is raised. ```python my_list = [1, 2, 3] for item in my_list: print(item) ``` - **While Loop:** You can manually iterate using a while loop with `next()`, handling the `StopIteration` exception. ```python my_list = [1, 2, 3] iterator = iter(my_list) while True: try: item = next(iterator) print(item) except StopIteration: break ``` # Multiple Choice Questions (MCQs) on Iterators and Iterables in Python ### 1. What is an **iterable** in Python? - A) An object that can return its elements one by one - B) A function that fetches data from an iterator - C) A loop that iterates over elements - D) A method that stops iteration ### 2. Which of the following is NOT an iterable in Python? - A) List - B) Tuple - C) Dictionary - D) Integer ### 3. What is the purpose of the `__iter__()` method in an iterable? - A) To convert an iterable into an integer - B) To return an iterator object - C) To fetch the next element in an iterable - D) To initialize a for loop ### 4. How do you convert an iterable into an iterator in Python? - A) Using the `next()` function - B) Using the `for` loop - C) Using the `iter()` function - D) Using the `__next__()` method ### 5. What exception is raised when there are no more items to return from an iterator? - A) ValueError - B) KeyError - C) StopIteration - D) TypeError ### 6. Which method in an iterator is responsible for fetching the next element? - A) `__iter__()` - B) `__next__()` - C) `next()` - D) `iter()` ### 7. Given the code snippet below, what will be the output? ```python my_list = [1, 2, 3] my_iterator = iter(my_list) print(next(my_iterator)) print(next(my_iterator)) ``` - A) 1, 2 - B) 1, 3 - C) 1, 2, 3 - D) Error ### 8. Which of the following statements is true about iterators and iterables? - A) Every iterator is an iterable, but not every iterable is an iterator. - B) Every iterable is an iterator, but not every iterator is an iterable. - C) Iterators and iterables are the same thing in Python. - D) Iterables raise `StopIteration`, but iterators do not. ### 9. How can you create a custom iterator in Python? - A) By defining a class with `__iter__()` and `__next__()` methods - B) By using a `for` loop to create an iterable - C) By implementing a generator function - D) By creating a list or dictionary ### 10. What will happen if we call `next()` on an iterator that has no remaining elements? - A) It will return `None` - B) It will loop back to the first element - C) It will raise a `StopIteration` exception - D) It will return the last element again ### 11. Which of the following is an **iterator** in Python by default? - A) List - B) String - C) File object - D) Dictionary ### 12. What does the `next()` function do in Python? - A) It creates an iterable object. - B) It returns the next element from an iterator. - C) It reverses an iterable. - D) It converts a string to a list. ### 13. What exception is raised when the `__next__()` method reaches the end of an iterator? - A) IndexError - B) KeyError - C) StopIteration - D) AttributeError ### 14. Which of the following types is NOT iterable in Python? - A) List - B) Set - C) Integer - D) Dictionary ### 15. How can you check if an object is an iterable? - A) Use `iter()` function on the object - B) Use `next()` function on the object - C) Check if it implements `__next__()` method - D) Check if it implements `__iter__()` method ### 16. Which of the following code snippets will result in a `StopIteration` exception? - A) ```python numbers = [1, 2, 3] iterator = iter(numbers) print(next(iterator)) print(next(iterator)) print(next(iterator)) print(next(iterator)) ``` - B) ```python for i in range(3): print(i) ``` - C) ```python my_set = {1, 2, 3} for element in my_set: print(element) ``` - D) ```python data = {"name": "John"} for key in data: print(key) ``` ### 17. How many times will `next()` be called successfully before raising a `StopIteration` exception? ```python colors = ['red', 'blue'] iterator = iter(colors) next(iterator) next(iterator) next(iterator) ``` - A) 1 - B) 2 - C) 3 - D) 0 ### 18. What will be the output of the following code? ```python my_tuple = (1, 2, 3) iterator = iter(my_tuple) print(next(iterator)) print(next(iterator)) ``` - A) 1 2 - B) 1 3 - C) 1 2 3 - D) Error ### 19. Can a Python `for` loop work with both iterables and iterators? - A) Yes - B) No ### 20. If you define a custom iterator class, which method must it implement to become an iterable itself? - A) `__next__()` - B) `__len__()` - C) `__iter__()` - D) `__getitem__()` ### 21. Which of the following is the correct way to create an iterator from a list in Python? A) `my_list.iter()` B) `iter(my_list)` C) `my_list.next()` D) `list(my_list)` ### 22. What happens when you call `next()` on an iterator that has already reached the end? A) It returns the first element again. B) It raises a `ValueError`. C) It returns `None`. D) It raises a `StopIteration` exception. ### 23. What is the primary purpose of an iterator? A) To store elements B) To loop through elements one at a time C) To modify elements D) To create new iterables ### 24. Which of the following types can be converted into an iterator? A) List B) String C) Set D) All of the above ### 25. What will the following code output? ```python numbers = [10, 20, 30] it = iter(numbers) print(next(it)) print(next(it)) ``` - A) 10 20 - B) 10 30 - C) 20 30 - D) 30 10 ### 26. What method should be implemented to allow an object to be used in a `for` loop? - A) `__iter__()` - B) `__next__()` - C) `__len__()` - D) `__contains__()` ### 27. If you have an iterator, how can you reset it to start iterating from the beginning again? - A) Recreate the iterator using the iter() function - B) Call the **iter**() method - C) Use the reset() method - D) It cannot be reset ### 28. What does calling next() on an iterator return? - A) The first element of the iterable - B) The next element of the iterable - C) A random element from the iterable - D) None of the above ### 29. Which of the following can raise a `StopIteration` exception? - A) A custom iterator class - B) A for loop - C) A list comprehension - D) A dictionary ### 30. What is the main difference between iterators and generators? - A) Generators are created using classes; iterators are not. - B) Iterators can store elements; generators cannot. - C) Generators automatically implement `__iter__()` and `__next__()` methods. - D) There is no difference; they are the same thing. ### Key: 1: A 2: D 3: B 4: C 5: C 6: B 7: A 8: A 9: A 10: C 11: C 12: B 13: C 14: C 15: A 16: A 17: B 18: A 19: A 20: C 21: B 22: D 23: B 24: D 25: A 26: A 27: A 28: B 29: A 30: C