# 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