0% found this document useful (0 votes)
12 views4 pages

Iterators Generators

The document explains Python iterators and generators, highlighting their distinct characteristics and use cases. Iterators are objects that implement the iterator protocol with methods `__iter__()` and `__next__()`, while generators simplify iterator creation using the `yield` statement. Both tools enable efficient iteration over data, with generators being more memory-efficient and easier to implement.

Uploaded by

temweb9182
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
12 views4 pages

Iterators Generators

The document explains Python iterators and generators, highlighting their distinct characteristics and use cases. Iterators are objects that implement the iterator protocol with methods `__iter__()` and `__next__()`, while generators simplify iterator creation using the `yield` statement. Both tools enable efficient iteration over data, with generators being more memory-efficient and easier to implement.

Uploaded by

temweb9182
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 4

### **Python Iterators and Generators**

In Python, **iterators** and **generators** are tools that enable e cient iteration over data.
While they are closely related, they have distinct characteristics and use cases.

---

### **Iterators**

An **iterator** is an object in Python that implements the **iterator protocol**. This protocol
consists of two methods:

1. `__iter__()`: Returns the iterator object itself. This allows the object to be used in `for` loops or
other iteration contexts.
2. `__next__()`: Returns the next item from the iterator. If there are no more items to return, it
raises a `StopIteration` exception.

#### Example: Creating and Using an Iterator

```python
class Counter:
def __init__(self, low, high):
self.current = low
self.high = high

def __iter__(self):
return self # The iterator object itself

def __next__(self):
if self.current > self.high:
raise StopIteration # End of iteration
else:
value = self.current
self.current += 1
return value

# Using the iterator


counter = Counter(1, 5)
for number in counter:
print(number)
```

**Output**:
```
1
2
3
4
5
```

#### Key Points:


- Iterators do not store the entire sequence in memory; they generate items on demand.
- Custom iterators give you ne control over the iteration process.
fi
ffi
---

### **Generators**

A **generator** is a simpler way to create iterators using functions or expressions. Generators


use the `yield` statement to produce values lazily, one at a time, without storing the entire
sequence in memory.

#### How Generators Work


- When a generator function is called, it does not execute immediately but returns a generator
object.
- The `yield` statement pauses the function, saving its state, and returns the value to the caller.
- When `__next__()` is called on the generator, execution resumes from where it was paused.

#### Example: Generator Function

```python
def countdown(start):
while start > 0:
yield start
start -= 1

# Using the generator


for number in countdown(5):
print(number)
```

**Output**:
```
5
4
3
2
1
```

---

#### Generator Expressions

A generator expression is a concise way to create generators, similar to list comprehensions


but without building a full list in memory.

```python
squares = (x * x for x in range(5))
for square in squares:
print(square)
```

**Output**:
```
0
1
4
9
16
```

---

### **Comparison: Iterators vs Generators**

| Feature | Iterators | Generators |


|---------------------|-----------------------------------------|---------------------------------------------|
| **Creation** | De ned by creating a class with `__iter__` and `__next__`. | De ned using a
function with `yield`. |
| **Ease of Use** | More complex to implement. | Simple and concise. |
| **State Handling** | You manage state explicitly. | State is managed automatically by
Python. |
| **Memory Usage** | E cient, as items are generated on demand. | Even more memory-
e cient. |

---

### **Advanced Examples**

#### In nite Generator

Generators are ideal for representing in nite sequences.

```python
def in nite_sequence():
num = 0
while True:
yield num
num += 1

# Using the in nite generator


in nite_gen = in nite_sequence()
for _ in range(5):
print(next(in nite_gen))
```

**Output**:
```
0
1
2
3
4
```

---

#### Combining Generators and Iterators

Generators can be used as building blocks for creating more complex iterators.
ffi
fi
fi
fi
fi
fi
fi
fi
ffi
fi
fi
```python
class Fibonacci:
def __init__(self, max_count):
self.max_count = max_count

def __iter__(self):
a, b, count = 0, 1, 0
while count < self.max_count:
yield a
a, b = b, a + b
count += 1

# Using the Fibonacci generator


for num in Fibonacci(10):
print(num)
```

**Output**:
```
0
1
1
2
3
5
8
13
21
34
```

---

### **Advantages of Generators**


1. **Memory E ciency**: They generate items on demand, making them suitable for handling
large datasets or streams of data.
2. **Lazy Evaluation**: Execution pauses at `yield` and resumes on demand, allowing for
e cient processing pipelines.
3. **Readability**: Code is simpler and more concise compared to custom iterator classes.

---

### **Key Takeaways**


- Iterators are a low-level implementation of the iteration protocol, giving you ne-grained
control.
- Generators provide a high-level, Pythonic way to create iterators with minimal code.
- Both are essential tools for working with streams of data or sequences that are too large to t
into memory.
ffi
ffi
fi
fi

You might also like