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.