tushar.pyc Profile picture
Metaprogramming • Python • @DeepSourceHQ

Jan 7, 2023, 7 tweets

Python Dunder of the Day 5: ✨__next__✨

We learned about __iter__ yesterday, and how it is used to create custom iterables.

But the way we did it was sort of a hack: By using `yield`, we just returned a generator from `__iter__()`.

In general, an iterable returns an iterator:

So to create an iterable, we need to first create an iterator.

🐍To create an iterator, you just need a class that defines a `__next__()` method. that method should just return the next value:

If we return this iterator object from our `MyIterable` class, our class will now forever return 42:

Let's look back at how a `for` loop works internally: It gets the iterator from `__iter__`, and then repeatedly calls `next()` on it.

A `next(i)` call is practically the same as `i.__next__()`, which means we have to make `__next__` return the next value.

Knowing all this, we can create an iterator that returns one item from a sequence, one by one, by getting `items[0]`, `items[1]`, ... until it runs out.

✨Here's how:

The previous example is big, but simple in essence:

- The iterator starts with a list of items and an index of 0
- On every __next__() call, it returns the next number in the list
- Once it runs out, it raises StopIteration

✨That's the internals of iteration.

e.g. a Reversed:

Now note that:
- An iterable needs to return an iterator in `__iter__`
- An iterator needs to define a `__next__`

So if you make a class that defines both, and make `__iter__(self)` just returns `self`, it'll work the same way.

✨So objects can be both iterable and an iterator:

Share this Scrolly Tale with your friends.

A Scrolly Tale is a new way to read Twitter threads with a more visually immersive experience.
Discover more beautiful Scrolly Tales like this.

Keep scrolling