# Generators

## Iterators

Object that enables a programmer to traverse a container, particularly lists. However, an iterator performs traversal and gives access to data elements in a container, but does not perform iteration. You might be confused so lets take it a bit slow. There are three parts namely:

* Iterable
* Iterator
* Iteration

All of these parts are linked to each other.

### 3.1. Iterable

Any object in Python which has an `__iter__` or a `__getitem__` method defined which returns an **iterator** or can take indexes (You can read more about them [here](https://stackoverflow.com/a/20551346)).&#x20;

Any object which can provide us with an **iterator**.

### 3.2. Iterator

Any object in Python which has a `next` (Python2) or `__next__` method defined.&#x20;

### 3.3. Iteration

The process of taking an item from something e.g a list.

### 3.4. Generators

Generators are **iterators, but you can only iterate over them once**

**They do not store all the values in memory, they generate the values on the fly**.

You use them by iterating over them, either with a ‘for’ loop or by passing them to any function or construct that iterates.

Most of the time `generators` are implemented as functions. However, **they do not `return` a value, they `yield`it**.

Example of a `generator` function:

```python
def generator_function():
    for i in range(10):
        yield i

for item in generator_function():
    print(item)

# Output: 0
# 1
# 2
# 3
# 4
# 5
# 6
# 7
# 8
# 9
```

Generators are **best for calculating large sets of results (particularly calculations involving loops themselves) where you don’t want to allocate the memory for all results at the same time**.

Example calculates fibonacci numbers:

```python
# generator version
def fibon(n):
    a = b = 1
    for i in range(n):
        yield a
        a, b = b, a + b
```

Now we can use it like this:

```python
for x in fibon(1000000):
    print(x)
```

This way we would not have to worry about it using a lot of resources.&#x20;

&#x20;We can iterate over `generators` only once but we haven’t tested it.&#x20;

**`next()`: allows us to access the next element of a sequence**. So let’s test out our understanding:

```python
def generator_function():
    for i in range(3):
        yield i

gen = generator_function()
print(next(gen))
# Output: 0
print(next(gen))
# Output: 1
print(next(gen))
# Output: 2
print(next(gen))
# Output: Traceback (most recent call last):
#            File "<stdin>", line 1, in <module>
#         StopIteration
```

**After yielding all the values `next()` caused a `StopIteration` error (**&#x61;ll the values have been yielded).

Do you know that a few **built-in data types in Python also support iteration**? Let’s check it out:

```python
my_string = "Yasoob"
next(my_string)
# Output: Traceback (most recent call last):
#      File "<stdin>", line 1, in <module>
#    TypeError: str object is not an iterator
```

The error says that **`str` is not an iterator. Well it’s right! It’s an iterable but not an iterator. This means that it supports iteration but we can’t iterate over it directly.** So how would we iterate over it? It’s time to learn about one more **built-in function, `iter`**. It returns an `iterator` object from an iterable. While an `int` isn’t an iterable, we can use it on string!

```python
int_var = 1779
iter(int_var)
# Output: Traceback (most recent call last):
#   File "<stdin>", line 1, in <module>
# TypeError: 'int' object is not iterable
# This is because int is not iterable

my_string = "Yasoob"
my_iter = iter(my_string)
print(next(my_iter))
# Output: 'Y'
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://ricardomol.gitbook.io/notes/backend/python/generators.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
